非常奇怪的行为:具有模板构造函数的类只有一个参数

时间:2011-12-20 09:25:07

标签: c++ templates constructor

最近,当我的类具有只接受一个参数的模板构造函数时,我遇到了一种奇怪的行为。在某些情况下,该课程根本无法初始化。

#include <iostream>

struct Foo
{
    template<typename T>
    Foo(const T& x)
    {
        std::cout << "--" << x << std::endl;
    }
};

int main(int, char**)
{
    Foo f(std::string());

    std::cout << "++" << f << std::endl;
    return 0;
}

我所拥有的是具有您看到的构造函数的Foo结构。在main中,我创建了一个带有空std :: string的新Foo实例。示例编译,输出为:

++1

WTF ???您可能已经注意到这有三个问题。首先,构造函数从未被调用,其次f被打印为“1”,第三,没有重载的运算符&lt;&lt;使用cout打印Foo,尽管编译器从不抱怨。这意味着f不是一种Foo。

我稍微改变了一下这个例子:

int main(int, char**)
{
    Foo f(std::string(""));

    std::cout << "++" << f << std::endl;
    return 0;
}

...并且编译器抛出一个错误,即没有重载的运算符&lt;&lt;这是正常的。

int main(int, char**)
{
    Foo f(std::string("Hello"));
    return 0;
}

现在输出是:

--Hello

再次正常。

问题是当向Foo :: Foo传递空对象时,无论是std :: string()还是float()或any_type()。我在GCC 4.4和4.6中测试了这个例子,我发现这种行为非常意外。

你有什么看法?这是一个GCC错误还是我错过了什么?

2 个答案:

答案 0 :(得分:5)

Foo f(std::string());

它似乎没有像你想象的那样创建Foo类型的实例。

相反,它声明了一个名为f的函数,其返回类型为Foo,参数类型为函数类型(不带参数并返回std::string)。

与:

相同
Foo f(std::string (*)()); //same as yours

这和你的函数声明的唯一区别在于你的情况下参数类型是函数类型(最终衰变为函数指针类型无论如何),在我的例子中,参数类型是函数指针类型(它不需要衰减成指针类型)。

至于它打印++1的原因是因为它调用operator<<并将void*作为参数,并且此函数打印函数的地址。

现在,如果你想声明一个对象,那么你需要使用额外的parens:

Foo f((std::string())); //notice the extra parens!

这声明了一个对象,并调用构造函数:http://ideone.com/Px815


另见本主题:

答案 1 :(得分:2)

你正在经历臭名昭着的C ++ Most vexing parse。在你的第一个例子中

 Foo f(std::string());

被解析为函数声明,因此不会调用构造函数。