如果const T&是"只读引用",那为什么T t(T())是个函数声明而不是对象实例化?

时间:2022-10-29 12:19:52
我知道: const T&可以绑定左值,也可以绑定右值(以及字面常量),例如:

void f(const int& i){}
int main(void)
{
    int i = 1;
    f(i);
    f(2);
    const int&r1 = i;
    const int&r2 = 2;
    return 0;
}

这都没有问题,那么为什么下面的代码(来自另一个帖子)

class X
{
public:
    X(int i){ cout << __FUNCTION__ << endl; }
    X(){ cout << __FUNCTION__ << endl; }
    X(const X&){ cout << __FUNCTION__ << endl; }
    X(X&&){ cout << __FUNCTION__ << endl; }
};
int main(void)
{
    X x(X());
    return 0;
}

main函数当中的X x(X())被编译器认为是一个函数声明,而不是一个x变量的实例呢? 如果const X&可以绑定X()这样的临时变量(右值),为什么不是用X的拷贝构造函数,构造了一个x?
之前有一位大侠指出如果写成X x((X())),就是调用了一个默认对象的构造。但是这也不是我期待的:这样改的效果,似乎是一个函数声明加一个默认构造,而没有我期待的拷贝构造。

我希望知道语法上的原因,为什么这里X x(X())是一个函数声明?
非常感谢。。。。。。。。

10 个解决方案

#1


X x( X());  
单独把X() 拿出来做一句话执行确实是构造了一个匿名X对象。
但是放在整句话中情况就不一样了, 编译器看到这句话的时候一定会将它看做一个函数声明, X()变成了函数形参
理由:  在编译阶段X()不会为你构建出一个X对象,不会为X() 构建出的对象在内存中开辟一块空间, 构建对象的过程是在程序执行过程中构建的, 既然X() 不是一个对象, 那么又怎么调用拷贝构造函数呢,  这就是静态语言

你希望看到拷贝构造,何不显式的写出来
X x1;
X x2 = x1; //调用拷贝构造函数

#2


我都看不明白第一份代码是在干啥·····哪个大哥能给我解释一下这个操作的目的是啥。

#3


most vexing parse。这是parse阶段的二义性,它既可以解释成函数声明也可以解释成对象声明,既然标准规定parse成前者,那你再认为后者怎么有道理也是没用的。
要达到你的目的你需要多写一组括号X x((X()));或者你既然在C++11了,可以用unified initialization:X x{X{}};

#4


X x(X())
怎么作为一个函数声明解析呢
x是函数名,他的参数是什么类型呢:X()显然不是一个类型

#5


引用 4 楼 hnwyllmm 的回复:
X x(X())
怎么作为一个函数声明解析呢
x是函数名,他的参数是什么类型呢:X()显然不是一个类型


X x(X());
相当于
X x(X (*)());


#include <iostream>
using namespace std;

class X
{
};

X f1()
{
    X x;

    cout << __PRETTY_FUNCTION__ << endl;

    return x;
}

X f2()
{
    X x;

    cout << __PRETTY_FUNCTION__ << endl;

    return x;
}

int main(void)
{
    X x(X());

    x(f1);
    x(f2);
    return 0;
}

X x(X (*pf)())
{

    cout << __PRETTY_FUNCTION__ << endl;

    return pf();
}

#6


因为标准说了,凡是既能理解为声明,又能理解为定义的文字,都统一按声明处理。

#7


引用 6 楼 ri_aje 的回复:
因为标准说了,凡是既能理解为声明,又能理解为定义的文字,都统一按声明处理。


这个在标准里面的什么章节呢?
我手边的文档是ISO+IEC+14882-2011的c++标准。

#8


引用 5 楼 mymtom 的回复:

谢谢你的回复,那如何解释如果我把main函数改成了:
[code]
#include<vector>
#include<iostream>
using namespace std;
class X
{
public:
    X(int i){ cout << __FUNCTION__ << endl; }
    X(){ cout << "default ctor" << endl; }
    X(const X&){ cout << "copy constructor" << endl; }
    X(X&&){ cout << "move constructor" << endl; }
};
int main(void)
{
    X x((X())); // 这里改变了,增加了一层括号。
    return 0;
}[/code]
为什么打印出了一个default ctor,
(1) 如果还是一个声明,就不应该执行任何东西
(2) 如果是对象创建,那么是不是应该创建了两个对象,一个临时对象X(),一个用拷贝构造函数创建的x

是这样的吗?

#9


c++优先解释为函数

#10


引用 7 楼 aserre3e 的回复:
Quote: 引用 6 楼 ri_aje 的回复:

因为标准说了,凡是既能理解为声明,又能理解为定义的文字,都统一按声明处理。


这个在标准里面的什么章节呢?
我手边的文档是ISO+IEC+14882-2011的c++标准。

c++11 8.2/1

#1


X x( X());  
单独把X() 拿出来做一句话执行确实是构造了一个匿名X对象。
但是放在整句话中情况就不一样了, 编译器看到这句话的时候一定会将它看做一个函数声明, X()变成了函数形参
理由:  在编译阶段X()不会为你构建出一个X对象,不会为X() 构建出的对象在内存中开辟一块空间, 构建对象的过程是在程序执行过程中构建的, 既然X() 不是一个对象, 那么又怎么调用拷贝构造函数呢,  这就是静态语言

你希望看到拷贝构造,何不显式的写出来
X x1;
X x2 = x1; //调用拷贝构造函数

#2


我都看不明白第一份代码是在干啥·····哪个大哥能给我解释一下这个操作的目的是啥。

#3


most vexing parse。这是parse阶段的二义性,它既可以解释成函数声明也可以解释成对象声明,既然标准规定parse成前者,那你再认为后者怎么有道理也是没用的。
要达到你的目的你需要多写一组括号X x((X()));或者你既然在C++11了,可以用unified initialization:X x{X{}};

#4


X x(X())
怎么作为一个函数声明解析呢
x是函数名,他的参数是什么类型呢:X()显然不是一个类型

#5


引用 4 楼 hnwyllmm 的回复:
X x(X())
怎么作为一个函数声明解析呢
x是函数名,他的参数是什么类型呢:X()显然不是一个类型


X x(X());
相当于
X x(X (*)());


#include <iostream>
using namespace std;

class X
{
};

X f1()
{
    X x;

    cout << __PRETTY_FUNCTION__ << endl;

    return x;
}

X f2()
{
    X x;

    cout << __PRETTY_FUNCTION__ << endl;

    return x;
}

int main(void)
{
    X x(X());

    x(f1);
    x(f2);
    return 0;
}

X x(X (*pf)())
{

    cout << __PRETTY_FUNCTION__ << endl;

    return pf();
}

#6


因为标准说了,凡是既能理解为声明,又能理解为定义的文字,都统一按声明处理。

#7


引用 6 楼 ri_aje 的回复:
因为标准说了,凡是既能理解为声明,又能理解为定义的文字,都统一按声明处理。


这个在标准里面的什么章节呢?
我手边的文档是ISO+IEC+14882-2011的c++标准。

#8


引用 5 楼 mymtom 的回复:

谢谢你的回复,那如何解释如果我把main函数改成了:
[code]
#include<vector>
#include<iostream>
using namespace std;
class X
{
public:
    X(int i){ cout << __FUNCTION__ << endl; }
    X(){ cout << "default ctor" << endl; }
    X(const X&){ cout << "copy constructor" << endl; }
    X(X&&){ cout << "move constructor" << endl; }
};
int main(void)
{
    X x((X())); // 这里改变了,增加了一层括号。
    return 0;
}[/code]
为什么打印出了一个default ctor,
(1) 如果还是一个声明,就不应该执行任何东西
(2) 如果是对象创建,那么是不是应该创建了两个对象,一个临时对象X(),一个用拷贝构造函数创建的x

是这样的吗?

#9


c++优先解释为函数

#10


引用 7 楼 aserre3e 的回复:
Quote: 引用 6 楼 ri_aje 的回复:

因为标准说了,凡是既能理解为声明,又能理解为定义的文字,都统一按声明处理。


这个在标准里面的什么章节呢?
我手边的文档是ISO+IEC+14882-2011的c++标准。

c++11 8.2/1