【发布时间】:2017-02-23 09:15:01
【问题描述】:
我最近尝试制作一个 sfinae 类型特征来检测一个类是否包含名为 construct 的特定模板静态函数。
我带来了这个实现:
template<typename T, typename... Args>
struct has_template_construct_helper {
private:
template<typename U, typename... As>
static std::true_type test(decltype(&U::template construct<As...>)*);
template<typename...>
static std::false_type test(...);
public:
using type = decltype(test<T, Args...>(nullptr));
};
template<typename T, typename... Args>
using has_template_construct = typename has_template_construct_helper<T, Args...>::type;
我认为那没关系,确实如此。我试着用 gcc 和 clang 来测试我的特性:
struct TestStruct {
template<typename... Args>
static auto construct(int a, double b, Args... args) -> decltype(std::make_tuple(a, b, args...)) {
return std::make_tuple(1, 2.3, std::forward<Args>(args)...);
}
};
// didn't fire! Hurrah!
static_assert(has_template_construct<TestStruct, std::string>::value, "Don't pass the test");
它对两个编译器都有效。
但是,一旦我添加了转发引用,clang 就开始抱怨:
struct TestStruct {
template<typename... Args>
static auto construct(int a, double b, Args&&... args) -> decltype(std::make_tuple(a, b, std::forward<Args>(args)...))
{
return std::make_tuple(1, 2.3, std::forward<Args>(args)...);
}
};
// fires on clang :(
static_assert(has_template_construct<TestStruct, std::string>::value, "Don't pass the test");
这里是 coliru 的代码 sn-p:GCC, Clang
我的问题是:GCC 和 Clang 之间哪一个是错误的,我该如何修复我的代码以使其在两个编译器上都工作?
好吧,我试过了,现在我更困惑了。使用std::declval 时,它在clang 中恢复正常!
struct TestStruct {
template<typename... Args>
static auto construct(int a, double b, Args&&... args) -> decltype(std::make_tuple(a, b, std::declval<Args>()...))
{
return std::make_tuple(1, 2.3, std::forward<Args>(args)...);
}
};
// uh?? Works in clang?
static_assert(has_template_construct<TestStruct, std::string>::value, "Don't pass the test");
【问题讨论】:
-
取消注释
test(...)并查看替换期间的实际错误是什么。这会有所帮助。 -
“不适用于 std::forward”是什么意思?没有一种类型是不能调用 std::forward 且编译时已知结果的类型。
-
我认为这是clang中的一个错误。添加转发引用使其认为构造方法存在重载,因此会抛出错误。
标签: c++ c++11 templates clang sfinae