在使用可变模板时,遵循clang (注意:为了回答这个问题,不一定要去那里),对于以下模板重载函数,我发现了this SO question (3.8)和g++ (6.1)的不同行为:
template <class... Ts>
struct pack { };
template <class a, class b>
constexpr bool starts_with(a, b) {
return false;
}
template <template <typename...> class PACK_A,
template <typename...> class PACK_B, typename... Ts1, typename... Ts2>
constexpr bool starts_with(PACK_A<Ts1..., Ts2...>, PACK_B<Ts1...>) {
return true;
}
int main() {
std::cout << std::boolalpha;
std::cout << starts_with(pack<int, float, double>(),
pack<float, int, double>()) << std::endl;
std::cout << starts_with(pack<int, float, double>(),
pack<int, float, double, int>()) << std::endl;
std::cout << starts_with(pack<int, float, double>(),
pack<int, float, int>()) << std::endl;
std::cout << starts_with(pack<int, float, double>(),
pack<int, float, double>()) << std::endl;
std::cout << starts_with(pack<int, float, double>(),
pack<int>()) << std::endl;
}
代码:http://coliru.stacked-crooked.com/a/b62fa93ea88fa25b
输出
|---|-----------------------------------------------------------------------------|
| # |starts_with(a, b) | expected | clang (3.8) | g++ (6.1) |
|---|-----------------------------------|-------------|-------------|-------------|
| 1 |a: pack<int, float, double>() | false | false | false |
| |b: pack<float, int, double>() | | | |
|---|-----------------------------------|-------------|-------------|--------- ---|
| 2 |a: pack<int, float, double>() | false | false | false |
| |b: pack<int, float, double, int>() | | | |
|---|-----------------------------------|-------------|-------------|--------- ---|
| 3 |a: pack<int, float, double>() | false | false | false |
| |b: pack<int, float, int>() | | | |
|---|-----------------------------------|-------------|-------------|--------- ---|
| 4 |a: pack<int, float, double>() | true | true | false |
| |b: pack<int, float, double>() | | | |
|---|-----------------------------------|-------------|-------------|--------- ---|
| 5 |a: pack<int, float, double>() | true | false | false |
| |b: pack<int>() | | | |
|---|-----------------------------------------------------------------------------|
最后两种情况(4和5)是有问题的:我对更专业的模板的期望是错误的吗?如果是这样的话,在案例4中,谁是对的,clang还是g++?(请注意,代码编译时没有任何错误或警告,但结果不同)。
为了回答这个问题,我多次查看了规范(14.5.6.2 Partial ordering of function templates)和cppreference中的“更专门化”规则--似乎更专门化的规则应该会给出我所期望的结果(如果不是,可能会出现歧义错误,但事实也不是这样)。那么,我在这里错过了什么?
等待(1):请不要着急,带上Herb Sutter和他的template methods quiz的"prefer not to overload templates“。这些当然很重要,但是该语言仍然允许模板重载!(这确实是一个加强点,为什么您不应该重载模板--在某些边缘情况下,它可能会混淆两个不同的编译器,或者混淆程序员。但问题不在于是否使用它,而是:如果你使用它,正确的行为是什么?)。
等待(2):请不要着急带来其他可能的解决方案。当然有。这里有两个:one with inner struct和another with inner static methods。这两个都是合适的解决方案,都像预期的那样工作,但是关于上面的模板重载行为的问题仍然存在。
https://stackoverflow.com/questions/37924796
复制相似问题