繁体   English   中英

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

[英]Why does decltype return type fail for recursive template, while return type deduction works just fine?

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

constexpr auto test() -> bool;

template <typename T, typename... Rest>
constexpr auto test() -> decltype(test<Rest...>())
{
  return {};
}

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

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

gcc抱怨:

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

我想这是因为当decltype看到它时,甚至没有完全声明可变参数版本的测试。

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

constexpr auto test() -> bool;

template <typename T, typename... Rest>
constexpr auto test()
{
  return test<Rest...>();
}

似乎在这里充分宣布了test

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

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

一个问题是您的第一个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; }
};

现场演示


在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...>();
}

现场演示

在声明模板函数本身时,模板函数本身尚未声明。 因此,尾随返回类型decltype不可见。

您可以使用ADL解决此问题。 如果模板函数从与模板函数相同的命名空间中获取参数,则返回类型的查找将变得愿意查看模板函数本身。 这是因为模板在声明它们之前使用上下文在每个参数上使用ADL来查找其返回类型签名。

template<class...Ts> struct types {};

namespace bob{
  struct mytag{};
  constexpr auto test(mytag, types<>) -> bool{ return true; }

  template <typename T, typename... Rest>
  constexpr auto test(mytag, types<T,Rest...>)
  -> decltype( test( mytag{}, types<Rest...>{} ) )
  {
    return test(mytag{},types<Rest...>{});
  }
}
template<class...Ts>
constexpr auto test()
->decltype( bob::test( bob::mytag{}, types<Ts...>{} ) ){
  return bob::test( bob::mytag{}, types<Ts...>{} );
}

您可能需要constexpr types(){}; mytag类似,取决于编译器。

这也解决了test<>在原始代码中非法的事实。 根据我的经验,函数在传递(标记模板包装)值的类型方面做得更好。 重载更友好。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM