2017-06-13 82 views
4

我一直在寻找这个问题在这里找到Template function overload for type containing a type函数模板重载及编译器优化

凡OP user2079802为他/她的问题提供了这个代码:

我尝试做以下:

#include <iostream> 
#include <vector> 
#include <tuple> 

template <typename T> 
void f(T t) { 
    std::cout << "1" << std::endl; 
} 

template <typename T, typename V> 
void f(T<std::tuple<V>> t) { 
    std::cout << "2" << std::endl; 
} 

int main() { 
    f(std::list<double>{}); // should use first template 
    f(std::vector<std::tuple<int>>{}); // should use second template 
} 

在C++ 14中这样做的最简单方法是什么?我认为我可以通过这种方式进行模式匹配,但编译器不会拥有它。

而且songyuanyao提供这样的回答:

参数T作为模板的名称,所以它应该被声明为template template parameter模板。例如

template <template <typename...> class T, typename V> 
//  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 
void f(T<std::tuple<V>> t) { 
    std::cout << "2" << std::endl; 
} 

LIVE


这是没有提供实际上修正编译错误以及代码没有正常运行的答案。为了清楚起见,我正在询问关于此代码段的问题。 OP最初尝试对模板类型进行模式匹配,但对模板模板参数的语法不正确。当我通过我的IDE跑了答案,编译器&调试器{MSVS 2017年CE}在64位英特尔Windows 7计算机上运行我碰巧注意到它们的主要功能是,在OP的函数调用:

f(std::list<double>{}); 
f(std::vector<std::tuple<int>>{}); 

第二个函数调用实际上是调用第一个函数模板而不是第二个。这确实引起了几个问题:

  • 这是由于编译器优化?
  • 这是重载解析的结果吗?
  • 在编译器的底层实际发生了什么,它在 选择使用第二个函数模板?
  • 或者这是MSVC编译器的错误吗?
+0

呃,你会得到输出“1 2”吗?或者您是否从调试器中看到的结论得出了“第二个函数调用实际上调用第一个函数模板”的结论? –

+0

@DanielJour我打印的值是'1'而不是'2',因此它调用第一个函数而不是第二个函数。 –

+2

这是MSVC编译器中的一个错误。 –

回答

2

它实际上不是MSVC编译器中的错误。这实际上是标准中有关默认模板参数的模糊性的结果。

你看,std::vector实际上有2个模板参数:类型和分配器。

如果从重构问题的答案占分配器

template <typename T> 
void f(T t) { 
    std::cout << "1" << std::endl; 
} 

template <template <typename...> class T, typename V> 
void f(T<std::tuple<V>, std::allocator<std::tuple<V>>> t) { 
    std::cout << "2" << std::endl; 
} 

它会在所有的编译器正常工作:msvc demogcc democlang demo

Here's the original defect report(CWG 150)

P0522R0有最新的讨论,2016年11月,他们提出,匹配您在songyuanyao的回答中引用的那种部分模板将根据标准是正确的。

P0522R0中提出的更改正在纳入C++ 17标准(我选中的是N4296草案)。在标准最终确定之前,MSVC声称拥有完整的C++ 17支持,我不会称之为编译器中的错误。现在,他们承认,这个具体的提案还没有被纳入到他们的编译器中,因为VS 2017.3 [P2](source

+0

这看起来像一个稍微不同的问题。报告中的例子被三个主要的编译器拒绝,而OP的代码按照g ++和clang ++的预期工作。您提出的解决方案忽略了这一点。使用参数包的方式是我们不想知道或关心可能存在的其他模板参数。你的解决方案迫使程序员知道'T'接受两个参数,第二个参数是'std :: allocator <...>'(我们可以写'template Tclass T',即使在C++ 03中也是如此)。幸运的是,[修复]很容易(https://pastebin.com/FmKfgqQY)。 –

+0

@ n.m。显式使用'std :: allocator'是为了演示目的:-)。至于这是与报告不同的问题,我倾向于(恭敬地)不同意。在使用C++ 14选项[demo](https://wandbox.org/permlink/RTRvJJAicYDUkuND)的gcc中,OPs代码无法按预期工作,但它可以与C++ 17选项[demo](https ://wandbox.org/permlink/x0w1SsMvr0s1pDA1) – AndyG

+0

所以在gcc 6和7之间的行为已经改变了(我只检查了gcc 6)。 –