模板化类中的友元运算符的多个定义

时间:2017-02-03 14:41:52

标签: c++ gcc clang argument-dependent-lookup

我有以下代码段:

template < typename T1, typename T2 >
class Test
{
  public:
    Test() = default;

  private:    
    template < typename T1_, typename T2_ >
    friend Test< T1_, T2_ > operator*( const Test< T1_, T2_ >& lhs, const Test< T1_, T2_ >& rhs )
    {
        return Test< T1_, T2_ >();
    }
};

int main( int argc, char* argv[] )
{
    {
        Test< int, int > t1;
        Test< int, int > t2;
        Test< int, int > t3 = t1 * t2;
    }

    {
        Test< double, double > t1;
        Test< double, double > t2;
        Test< double, double > t3 = t1 * t2;
    }
}

使用clang 3.9,代码编译正常,使用gcc 6.3.1我收到以下错误:

redefinition of ‘template<class T1_, class T2_> Test<T1_, T2_> operator*(const Test<T1_, T2_>&, const Test<T1_, T2_>&)’
     friend Test< T1_, T2_ > operator*( const Test< T1_, T2_ >& lhs, const Test< T1_, T2_ >& rhs )

哪种编译器是对的?

如果是gcc,我怀疑,如何在课堂上正确声明模板化运算符*。对于依赖于参数的查找,我需要使用类内定义。

1 个答案:

答案 0 :(得分:3)

GCC是正确的,因为Test的每个实例都定义了模板operator*,它们的签名完全相同,不依赖于T1T2operator*不一定是这里的模板,只是Test的特定实例化的重载:

template < typename T1, typename T2 >
class Test
{
    friend Test operator*(const Test& lhs, const Test& rhs)
    {
        return Test();
    }
};

int main( int argc, char* argv[] )
{
    {
        Test< int, int > t1;
        Test< int, int > t2;
        Test< int, int > t3 = t1 * t2;
    }

    {
        Test< double, double > t1;
        Test< double, double > t2;
        Test< double, double > t3 = t1 * t2;
    }
}

这将定义operator*的两个非模板重载,每个实例化Test一个。