编译器如何评估模板函数?

时间:2017-06-23 11:25:05

标签: c++ c++11 templates metaprogramming

考虑以下可变参数模板函数:

template<typename T, typename... Args>
auto foo(Args... args) -> T[sizeof...(args)]
{
   T t[sizeof...(args)];
   // Maybe do some pack expansion/assignment
   return t;
}

实例化:

// total should be of type int[5];
auto total = foo(1,2,3,4,5);

我理解这不会编译,因为返回类型不可归类,但我不明白为什么它不可推导。

编译器在编译时是否知道这个函数,或者正在评估的函数部分的顺序是什么,这会阻止类型推导?

我怀疑这是由于函数sizeof...的调用,我认为它在运行时进行评估。如果是这样,是否有编译时的等价物?

2 个答案:

答案 0 :(得分:8)

您无法按值返回内置数组。请改用std::array

另外,就目前情况而言,您需要明确提供类型T作为模板参数,因为它不会出现在参数列表中。因此,编译器无需从中推断出它。

完整示例:

#include <array>

template<typename T, typename... Args>
auto foo(Args... args) -> std::array<T, sizeof...(args)>
{
   std::array<T, sizeof...(args)> t;
   // Maybe do some pack expansion/assignment
   return t;
}

int main () {
    auto a = foo<int>(1,2,3);
}

根据用例,您可以通过例如删除显式模板参数。使用包中所有元素的std::common_typestatic_assert它们都具有相同的类型并使用它。

此外,对于记录,sizeof...确实产生编译时常量。问题是,为了明确答案,编译器无法告诉T应该是什么。

答案 1 :(得分:7)

编译器无法推断T,因为你没有将T传递给函数参数。

auto total = foo<int>(1,2,3,4,5);

如果我们正确地将T手动作为模板参数 - 它将compile & work fine on G++7.1

或者,您可以从变量参数中简单地decltype所需的类型。

类似的东西:

template <typename T, typename...Args>
T getHead(T&& arg, Args&&...) {
     return arg;
}


template<typename... Args>
auto foo(Args... args)
{
     using TYPE = typename std::decay<decltype(getHead(args...))>::type;
     return std::array<TYPE, sizeof...(Args)>{ args... };
}

是的,使用std :: array,返回本地C风格的数组是未定义的行为。