GCC vs. Clang:"invalid use of incomplete type" std::d eclval 和模板专业化
gcc vs. clang: "invalid use of incomplete type" with std::declval and template specialization
我有一个方法fun
它包含在用于部分专用化的结构Impl
中。检查is_derived_from_template
用于确定泛型Impl::fun
是否可用于派生自特定模板的类型。否则,Impl
是部分显式专用的。
#include <iostream>
template <typename T, typename U>
struct Base{};
// Forward declaration
struct Foo;
struct Bar;
template <template<typename...> class T, typename U>
struct is_derived_from_template
{
private:
template<typename... Args>
static decltype(static_cast<const T<Args...>&>(std::declval<U>()), std::true_type{}) test(const T<Args...>&);
static std::false_type test(...);
public:
static constexpr bool value = decltype(test(std::declval<U>()))::value;
};
template <typename T, typename = void>
struct Impl
{
static void fun(T& x);
};
template <typename T>
struct Impl<T, typename std::enable_if<is_derived_from_template<Base, T>::value>::type>
{
static void fun(T& base)
{
std::cout << "Base" << std::endl;
}
};
template <>
void Impl<Foo>::fun(Foo& t)
{
std::cout << "Foo" << std::endl;
}
struct Foo {};
struct Bar : Base<int,double> {};
int main()
{
Foo foo;
Bar bar;
Impl<Foo>::fun(foo);
Impl<Bar>::fun(bar);
}
使用 gcc 编译此代码时,出现以下错误:
main.cpp: In instantiation of 'constexpr const bool is_derived_from_template<std::vector, Foo>::value':
main.cpp:33:15: required from here
main.cpp:15:48: error: invalid use of incomplete type 'struct Foo'
static constexpr bool value = decltype(test(std::declval<U>()))::value;
^
main.cpp:5:8: note: forward declaration of 'struct Foo'
struct Foo;
^
海湾合作委员会现场演示
但是,clang 编译此内容时没有错误,输出符合预期:
Foo
Base
叮当现场演示
- 两个编译器中哪一个是正确的?
- 如何修改我的代码以使其与 gcc 一起使用?
简化为
#include <utility>
void f(...);
class C;
using type = decltype(f(std::declval<C>()));
在 Clang 上编译,在 GCC 上出错。
我倾向于说 GCC 就在这里,因为通过 ...
传递类类型的对象需要复制,并且您不能复制不完整类型的东西。
如果需要,可以在SFINAE中使用指针:
template <template<typename...> class T, typename U>
struct is_derived_from_template
{
private:
template<typename... Args>
static decltype(static_cast<const T<Args...>&>(std::declval<U>()), std::true_type{}) test(const T<Args...>*);
static std::false_type test(...);
public:
static constexpr bool value = decltype(test(std::declval<U*>()))::value;
};
尽管在允许使用不完整类型实例化is_derived_from_template
时应谨慎,因为如果完整类型原来是从指定模板派生的,则很容易导致 ODR 冲突。
1. Clang
编译方式与GCC
等传统编译器略有不同。 GCC
是正确的,因为它与Clang
相比"传统"解析代码,并且您应该在使用它们之前定义您的类型。
你可以在这里找到一个比较。
2.变更:
// Forward declaration
struct Foo;
struct Bar;
自:
struct Foo {};
struct Bar : Base<int,double> {};
为我工作。
相关文章:
- 如何使用默认参数等选择模板专业化
- 模板化建造师专业化
- 类模板的成员功能的定义在单独的TU中完全专业化
- 部分专业化和嵌套模板
- 模板专业化可以进入我的.cpp吗?
- 别名模板的专业化 C++11 中没有开销的最佳替代方案
- 部分专业化和对标准::void_t<>的需求
- "专业化不参与超载"
- 特定好友功能专业化
- 是否可以混合使用SFINAE和模板专业化?
- 为什么在班级专业化上会出现错误?
- enable_if如何帮助选择类模板的专业化?
- std::initializer_list可以专业化吗?
- 派生类中纯虚拟基方法的专业化
- 使用 AppleClang 时来自 decltype( std::d evlcal<std::ostream>() << std::d eclval<T>() 的奇
- "expected a '>'"类模板专业化?
- Clang不会编译GCC会编译的模板专业化
- 我可以用clang AST从模板专业化中获得默认的模板参数吗
- 函数模板部分专业化-有什么解决方法吗
- GCC vs. Clang:"invalid use of incomplete type" std::d eclval 和模板专业化