功能模板重载分辨率&编译器优化

时间:2017-06-13 02:23:01

标签: c++ templates compiler-optimization overload-resolution

我在这里找到这个问题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。 e.g。

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

LIVE

提供的答案确实解决了编译错误,代码确实正常运行。为了清楚起见,我正在询问有关此代码段的问题。 OP最初尝试模式匹配模板类型,但模板模板参数的语法不正确。当我通过我的IDE运行答案时,Compiler&amp;在64位Intel Windows 7机器上运行的调试器{MSVS 2017 CE}我碰巧注意到OP的函数调用它们的主要功能:

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

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

  • 这是否由于编译器优化而发生?
  • 这是重载解决的结果吗?
  • 在编译器的引擎盖下实际发生了什么   是选择在第二个使用第一个功能模板吗?
  • 或者这是MSVC编译器的错误吗?

1 个答案:

答案 0 :(得分: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

以来,该特定提案尚未纳入其编译器