此代码在CodeGear 2009和Visual Studio 2010中编译,但不在gcc中编译。为什么呢?
class Foo
{
public:
operator int() const;
template <typename T> T get() const { return this->operator T(); }
};
Foo::operator int() const
{
return 5;
}
错误消息是:
test.cpp:在成员函数`T Foo :: get()const':
中
test.cpp:6:错误:'const class Foo'没有名为'operator T'的成员
答案 0 :(得分:9)
这是G ++中的一个错误。 operator T
是一个非限定的从属名称(因为它中包含T
,因此查找将根据其类型而不同)。因此,必须在实例化时查找它。标准规则
如果
,两个名称相同
- ...
- 它们是用相同类型形成的用户定义转换函数的名称。
因此,在operator关键字之后指定的类型名称不必以任何方式词汇匹配。您可以应用以下解决方法强制GCC将其视为从属名称
template<typename T, typename>
struct identity { typedef T type; };
class Foo
{
public:
operator int() const;
template <typename T> T get() const {
return this->identity<Foo, T>::type::operator T();
}
};
答案 1 :(得分:4)
我不确定C ++运算符名称的确切规则是什么,但我认为它试图调用operator T()
而不是operator int()
。为什么不直接使用演员:
template <typename T> T get() const { return static_cast<T>(*this); }
我没有测试过这个,但我相信这会或多或少地完成同样的事情。如果没有,应该有一种方法来实现这一点,而无需直接调用operator T()
。毕竟,这就是重载运营商的目的。
答案 2 :(得分:2)
如果我稍微修改代码:
template <typename T> T get() const { return operator T(); }
我在GCC中得到以下信息:
有 没有参数'运营商T' 取决于模板参数,所以a '运营商T'的声明必须是 可用(如果你使用 '-fpermissive',G ++会接受你的 代码,但允许使用 未声明的名称已弃用)
但是如果你要使用-fpermissive,整个事情只有在T = int
另一方面,为什么不这样做:
template <typename T> T get() const { return *this; }
这就是转换操作符的重点。
答案 3 :(得分:2)
我对此用例感到好奇。我想你可以这样说:
Foo f;
int x = f.get<int>();
但为什么不说:
Foo f;
int x = static_cast<int>(f);
输入稍长一些(虽然可以使用C演员表示法),但不需要任何箍跳。