模板和铸造操作员

时间:2010-04-19 21:27:51

标签: c++ templates casting operator-overloading

此代码在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'的成员

4 个答案:

答案 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演员表示法),但不需要任何箍跳。