在处理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支持?
答案 0 :(得分:5)
一个问题是您的第一个from datetime.datetime import now
重载不是函数模板,因此无法使用test
语法调用。
但是,test<>()
并不真正适用于递归的可变参数函数,因为返回类型是函数声明的一部分,因此在查找名称时不会声明重载。
你可以通过使用模板类来解决这个问题:
decltype
在C ++ 14中,您可以使第一个重载采用单个模板参数,第二个重载采用两个参数包:
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; }
};
答案 1 :(得分:4)
虽然声明了模板函数本身,但模板函数本身尚未声明。因此,尾随返回类型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<>
在原始代码中非法的事实。根据我的经验,函数在传递(标记模板包装)值的类型方面做得更好。重载更友好。