这段代码有效吗?使用gcc,不要与clang一起使用

时间:2014-10-25 19:29:39

标签: c++ templates g++ clang clang++

以下最小代码在g ++上编译,但不会在clang ++上编译:

template<class T>
T operator*(float a, const T& b)
{
    return b * a;
}

struct A{
    A operator*(float b) const
    {
        A a;
        return a;
    }
};

int main()
{
    A a;
    2.0f * a;
}

这是我得到的错误:

$ clang++ test.cpp 
test.cpp:2:3: error: overloaded 'operator*' must have at least one parameter of
      class or enumeration type
T operator*(float a, const T& b)
  ^
test.cpp:4:11: note: in instantiation of function template specialization
      'operator*<float>' requested here
        return b * a;
                 ^
test.cpp:18:10: note: in instantiation of function template specialization
      'operator*<A>' requested here
    2.0f * a;
         ^
1 error generated.

Clang 3.5版。这段代码有效吗? Clang有错误吗?

1 个答案:

答案 0 :(得分:2)

2.0f * a;实例化::operator*<A>。在该函数中,我们使用表达式b * a,如果查看(简化)类型,则为A * float。此时,编译器需要做出选择。那个*应该是全局函数::operator*<float>(因为右手参数是float),还是应该是A::operator*?对于我们人类来说,显然它应该是A::operator*,但从编译器的角度来看,它并不是立即清楚的。

那么编译器做什么?它首先尝试查找可以使用的所有operator*函数(之后,它会尝试确定要使用哪个函数)。 可以使用的operator*个函数之一是::operator*<float>。但等等,::operator*<float>是什么?它是float *(float, const float&)!我们做不到!你不能为基本类型重载运算符(想象一下,如果你重载int +(int, int)就会出现混乱,这样你就可以让1 + 2做一些与大家所期望的完全不同的事情。)

此时,该程序格式不正确。编译器甚至尝试实例化::operator*<float>这一事实使整个程序无效。所以,我们能做些什么?告诉编译器到底要做什么:

template<class T>
T operator*(float a, const T& b)
{
    // This prevents the compiler from instantiating ::operator*<float>
    return b.operator*(a);

    // The above is meant to illustrate how the fix needs to work: it needs
    // to avoid instantiating ::operator*<float>. Other methods can be used
    // (like SFINAE) that might be more elegant (check out Walter's answer
    // in the duplicate: https://stackoverflow.com/a/18596809/1287251), but
    // in the end any solution used must avoid ::operator*<float>.
}

struct A{
    A operator*(float b) const
    {
        A a;
        return a;
    }
};

int main()
{
    A a;
    2.0f * a;
}

简而言之,回答这个问题:不,代码无效。您必须阻止编译器尝试实例化::operator*<float>

This is explained by @dyp in the commentsby @TemplateRex in the duplicate question。但是,在我理解他们的意思之前,我必须多次阅读他们的回答。我试图在这个答案中简化一些事情。如果我能改进它,请告诉我!