gcc中的模糊重载,msvc没问题
Ambiguous overload in gcc, fine with msvc
下面的代码在msvc 18.00下可以正常编译,但在gcc 4.9.1下不能正常编译:
#include <type_traits>
template <int N> class Num { };
class Zero { };
template <int N, int M>
Num<N + M> operator+(Num<N>, Num<M>)
{
return {};
}
template <int N>
Zero operator+(Num<N>, Num<-N>)
{
return {};
}
int main()
{
Num<1> one;
Num<-1> mone;
Num<0> null;
auto a = one + one;
static_assert(std::is_same<decltype(a), Num<2>>::value, ":(");
auto b = one + mone;
static_assert(std::is_same<decltype(b), Zero>::value, ":(");
auto c = null + null;
static_assert(std::is_same<decltype(c), Zero>::value, ":(");
}
gcc的错误信息是:
ambiguous.cpp: In function 'int main()':
ambiguous.cpp:28:16: error: ambiguous overload for 'operator+' (operand types are 'Num<1>' and 'Num<-1>')
auto b = one + mone;
^
ambiguous.cpp:28:16: note: candidates are:
ambiguous.cpp:8:12: note: Num<(N + M)> operator+(Num<N>, Num<M>) [with int N = 1; int M = -1]
Num<N + M> operator+(Num<N>, Num<M>)
^
ambiguous.cpp:14:6: note: Zero operator+(Num<N>, Num<(- N)>) [with int N = 1]
Zero operator+(Num<N>, Num<-N>)
^
ambiguous.cpp:29:47: error: template argument 1 is invalid
static_assert(std::is_same<decltype(b), Zero>::value, ":(");
^
ambiguous.cpp:31:17: error: ambiguous overload for 'operator+' (operand types are 'Num<0>' and 'Num<0>')
auto c = null + null;
^
ambiguous.cpp:31:17: note: candidates are:
ambiguous.cpp:8:12: note: Num<(N + M)> operator+(Num<N>, Num<M>) [with int N = 0; int M = 0]
Num<N + M> operator+(Num<N>, Num<M>)
^
ambiguous.cpp:14:6: note: Zero operator+(Num<N>, Num<(- N)>) [with int N = 0]
Zero operator+(Num<N>, Num<-N>)
^
ambiguous.cpp:32:47: error: template argument 1 is invalid
static_assert(std::is_same<decltype(c), Zero>::value, ":(");
^
哪个编译器是正确的?
我讨厌这么说,但是MSVC是正确的,gcc 5.1和clang 3.6是错误的!为了简化,我们调用:
operator+(Num<1>, Num<-1>)
与过载:operator+(Num<N>, Num<M>)
operator+(Num<N>, Num<-N>)
两者显然都是可行的候选人。并且,根据[over.match.best]:
给定这些定义,一个可行函数
F1
被定义为优于另一个可行函数的函数F2
如果对于所有参数i
, ICSi(F1
)并不比ICSi(F2
)差,然后
- […]
- 根据14.5.6.2中描述的部分排序规则为
F1
和F2
是函数模板专门化,F1
的函数模板专门化程度更高F2
替换模板。
确定偏序的规则可以归结为:对于每个模板形参,合成一个新的类型/值,并尝试用它调用另一个重载。对于第一个重载,它变成operator+(Num<A>, Num<B>)
,不能调用operator+(Num<N>, Num<-N>)
。然而,第二个重载变成了operator+(Num<C>, Num<-C>)
,您可以使用它调用第一个重载。
因此,接受Num<-N>
的重载比接受Num<M>
的重载更专门化,因此应该明确地优先选择它。
相关文章:
- 警告处理为错误这里有什么问题
- MSVC中的宏观扩展问题
- 没有'str'成员在 GCC 和 Clang 'std::basic_ostream<char>',但 MSVC 没有问题
- 如何修复MSVC++(Microsoft Visual studio)中"macro overloading"的可变参数宏相关问题?
- 函数返回样式合乎逻辑,没问题
- 将早期 MSVC 版本生成的代码重新生成为较新版本时可能遇到的问题
- C++模板方法:为什么 Node<int> 没问题,但 Node 不行<float>?
- 在窗口上使用 clang 链接 msvc 内部函数时出现问题
- 简单的 constexpr 函数无法使用 GCC 编译(clang 没问题)
- visual MSVC编译器错误C2688:Microsoft C++ABI角大小写问题
- MSVC++2013调试与发布编译问题
- 当函数在头文件中列出时,未定义的引用,但如果我直接复制和粘贴代码则没问题
- 这个解决方案对MSVC的双重检查锁定错误和函数静态有什么问题?
- MinGW 与 MSVC 的 dll 库问题链接(未定义的引用)
- Std::将Std::unique_ptr对象移动到STL容器中.(MSVC编译器问题)
- 看起来除了加法,其他都没问题
- 为什么是wcout<< " ";没问题,但 wcout <<字符串();莫?
- MSVC 的问题包括
- Printf由于某种原因打印两次,cout似乎没问题
- gcc中的模糊重载,msvc没问题