为什么decltype返回类型对递归模板失败,而返回类型推导工作正常?

Rum*_*rak 4 c++ recursion decltype c++11 return-type-deduction

在处理C++ 11类型集时,我尝试实现此功能(剥离到最小):

constexpr auto test() -> bool;

template <typename T, typename... Rest>
constexpr auto test() -> decltype(test<Rest...>())
{
  return {};
}
Run Code Online (Sandbox Code Playgroud)

gcc和clang都对此感到窒息.Clang说:

test.cpp:54:40: error: 'Rest' does not refer to a value
constexpr auto test() -> decltype(test<Rest...>())
                                  ^
Run Code Online (Sandbox Code Playgroud)

gcc抱怨:

test.cpp:54:44: error: expected primary-expression before ‘...’ token
 constexpr auto test() -> decltype(test<Rest...>())
Run Code Online (Sandbox Code Playgroud)

我想这是因为在decltype查看它时,甚至没有完全声明测试的可变版本.

但是,当我在C++ 14中使用返回类型推导时,这编译得很好:

constexpr auto test() -> bool;

template <typename T, typename... Rest>
constexpr auto test()
{
  return test<Rest...>();
}
Run Code Online (Sandbox Code Playgroud)

似乎test在这里被认为是充分宣布的.

我想知道为什么这对decltype变体不起作用?即使我打开C++ 14支持?

PS:事实证明,我甚至无法调用C++ 14函数,所以也许整个事情都很糟糕......

Tar*_*ama 5

一个问题是您的第一个test重载不是函数模板,因此无法使用test<>()语法调用.

但是,decltype这并不适用于递归的可变参数函数,因为返回类型是函数声明的一部分,因此在查找名称时不会声明重载.

您可以使用模板类在C++ 11中解决此问题:

template <typename... Ts>
struct test;

template <typename T, typename... Ts>
struct test<T,Ts...> {
    static decltype(test<Ts...>::value()) value() { return test<Ts...>::value(); }   
};

template <>
struct test<> {
    static bool value() { return true; }
};
Run Code Online (Sandbox Code Playgroud)

现场演示


在C++ 14中,您可以使第一个重载采用单个模板参数,第二个采用两个参数包:

template <typename T>
constexpr auto test() -> bool { return true; }

template <typename T, typename U, typename... Rest>
constexpr auto test()
{
  return test<U,Rest...>();
}
Run Code Online (Sandbox Code Playgroud)

现场演示