Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/templates/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
SFINAE失败,类模板中的typedef引用了另一个类模板中的typedef 我一直在研究一种生成关于C++中其他类的编译时间信息的方法。在我将要询问的问题的一个最小示例中,这样一个包装器类: 包含定义包装类类型的typedef WrappedType;及 重载名为IsWrapper的结构模板,以指示它是一个包装类_C++_Templates_Sfinae_Typetraits_Enable If - Fatal编程技术网

SFINAE失败,类模板中的typedef引用了另一个类模板中的typedef 我一直在研究一种生成关于C++中其他类的编译时间信息的方法。在我将要询问的问题的一个最小示例中,这样一个包装器类: 包含定义包装类类型的typedef WrappedType;及 重载名为IsWrapper的结构模板,以指示它是一个包装类

SFINAE失败,类模板中的typedef引用了另一个类模板中的typedef 我一直在研究一种生成关于C++中其他类的编译时间信息的方法。在我将要询问的问题的一个最小示例中,这样一个包装器类: 包含定义包装类类型的typedef WrappedType;及 重载名为IsWrapper的结构模板,以指示它是一个包装类,c++,templates,sfinae,typetraits,enable-if,C++,Templates,Sfinae,Typetraits,Enable If,有一个名为WrapperTraits的结构模板,可用于确定包装类型层次结构的(非包装)根类型。例如,如果包装类是名为wrapper的类模板,wrapper的根类型将是int 在下面的代码片段中,我实现了一个名为GetRootType的递归结构模板,它定义了一个typedef RootType,它给出了包装类型T的根类型。WrapperTraits的给定定义只包含由GetRootType定义的根类型,但实际上它会有一些额外的成员。为了测试它,我编写了一个普通函数f,它接受int,以及一个重载函数模

有一个名为
WrapperTraits
的结构模板,可用于确定包装类型层次结构的(非包装)根类型。例如,如果包装类是名为
wrapper
的类模板,
wrapper
的根类型将是
int

在下面的代码片段中,我实现了一个名为
GetRootType
的递归结构模板,它定义了一个
typedef RootType
,它给出了包装类型
T
的根类型。
WrapperTraits
的给定定义只包含由
GetRootType
定义的根类型,但实际上它会有一些额外的成员。为了测试它,我编写了一个普通函数
f
,它接受
int
,以及一个重载函数模板
f
,它接受一个以
int
为根类型的任意包装类。我使用SFINAE来区分它们,在函数模板的返回类型中使用
std::enable_if
,检查
f
的参数的根类型是否为
int
(如果
f
的参数不是包装器,则尝试确定其根类型将失败)。在我提问之前,以下是代码片段:

#include <iostream>
#include <type_traits>


// Wrapper #######################################

template<class T>
struct Wrapper {typedef T WrappedType;};

template<class T, class Enable=void>
struct IsWrapper: std::false_type {};

template<class T>
struct IsWrapper<Wrapper<T> >: std::true_type {};


// WrapperTraits #######################################

template<
  class T,
  bool HasWrapper=
    IsWrapper<T>::value && IsWrapper<typename T::WrappedType>::value>
struct GetRootType {
  static_assert(IsWrapper<T>::value,"T is not a wrapper type");

  typedef typename T::WrappedType RootType;
};

template<class T>
struct GetRootType<T,true> {
  typedef typename GetRootType<typename T::WrappedType>::RootType RootType;
};

template<class T>
struct WrapperTraits {
  typedef typename GetRootType<T>::RootType RootType;
};


// Test function #######################################

void f(int) {
  std::cout<<"int"<<std::endl;
}

// #define ROOT_TYPE_ACCESSOR WrapperTraits  // <-- Causes compilation error.
#define ROOT_TYPE_ACCESSOR GetRootType    // <-- Compiles without error.

template<class T>
auto f(T) -> 
  typename std::enable_if<
    std::is_same<int,typename ROOT_TYPE_ACCESSOR<T>::RootType>::value
  >::type
{
  typedef typename ROOT_TYPE_ACCESSOR<T>::RootType RootType;

  std::cout<<"Wrapper<...<int>...>"<<std::endl;
  f(RootType());
}


int main() {
  f(Wrapper<int>());  
  return 0; 
}
我的问题是:<强> C++标准中的参数推导规则解释了为什么使用<代码> WrapperTraits <代码>会导致编译错误,但是使用<代码> GETROOTTYPE 不?< /强>请注意,我想问的是,为什么能够理解这个编译错误发生的原因。我不太感兴趣的是可以进行哪些更改以使其工作,因为我已经知道,将
WrapperTraits
的定义更改为this可以修复错误:

template<
  class T,
  class Enable=typename std::enable_if<IsWrapper<T>::value>::type>
struct WrapperTraits {
  typedef typename GetRootType<T>::RootType RootType;
};

template<class T>
struct WrapperTraits<T,typename std::enable_if<!IsWrapper<T>::value>::type> {
};
模板<
T类,
class Enable=typename std::Enable_if::type>
结构包装特性{
typedef typename GetRootType::RootType RootType;
};
模板
结构包装特性::类型>{
};

然而,如果有人能看到一种更优雅的方式来书写
f
WrapperTraits
,我会非常感兴趣的

你问题的第一部分是为什么失败。答案是在编译时级别,
&&
没有短路属性。这一行:

bool HasWrapper=IsWrapper<T>::value && IsWrapper<typename T::WrappedType>::value>

您遇到的问题是,SFINAE只发生在模板实例化的“即时上下文”(标准使用的术语,但定义不明确)中。
WrapperTraits
的实例化在
auto f()->…
实例化的直接上下文中,并且成功。不幸的是,
WrapperTraits
有一个格式错误的成员
RootType
。该成员的实例化不在直接上下文中,因此SFINAE不适用

为了让这个SFINAE按照您的意愿工作,您需要安排
WrapperTraits
不具有名为
RootType
的类型,而不是具有这样一个成员,而是具有格式错误的定义。这就是为什么更正后的版本可以按预期工作,尽管您可以通过重新排序来节省一些重复:

template<class T, class Enable=void>
struct WrapperTraits {};

template<class T>
struct WrapperTraits<T,typename std::enable_if<IsWrapper<T>::value>::type> {
  typedef typename GetRootType<T>::RootType RootType;
};
模板
结构包装特性{};
模板
结构包装特性{
typedef typename GetRootType::RootType RootType;
};
我可能会将整个traits系统编码为():

//void的普通实现\u t
模板结构voider{using type=void;};
模板
使用void\u t=typename voider::type;
//包装特性#######################################
//包装类型专门化WrappedType以公开它们包装的类型;
//类型T是WrappedType::type存在时的包装类型。
模板结构WrappedType{};
//GetRootType打开任何和所有包装层。
模板
结构GetRootType{
using type=T;//非WrappedType的根类型就是该类型本身。
};
//WrappedType的根类型是它所包装的类型的根类型。
模板
结构GetRootType:
GetRootType{};
//非包装类型没有包装特性。
模板
结构包装特性{};
//WrappedTypes有两个关联的类型:
//*WrappedType,已包装的类型
//*RootType,在一堆包装器中完全展开的类型。
模板
结构包装特性{
使用WrappedType=typename::WrappedType::type;
使用RootType=typename GetRootType::type;
};
//用于访问包装特性的方便别名
模板
使用WrappedType=typename WrapperTraits::WrappedType;
模板
使用WrapperRootType=typename WrapperTraits::RootType;
//一些包装纸#######################################
//包装器是一种包装类型
模板结构包装{};
模板
结构WrappedType{
使用类型=T;
};
//单元素数组是WrappedType
模板
结构WrappedType{
使用类型=T;
};
//单元素元组是WrappedType
模板
结构WrappedType{
使用类型=T;
};

虽然那里有很多机器,而且可能比你需要的更重。例如,可以取消
WrapperTraits
模板,而直接使用
WrappedType
GetRootType
。我无法想象您经常需要传递一个
WrapperTraits
实例化。

谢谢您的回答!不过,我现在意识到,我的问题有几点不清楚——我很快就会更新它。关于第一部分,我希望编译器尝试替换
intbool HasWrapper=IsWrapper<T>::value && IsWrapper<typename T::WrappedType>::value>
#include <iostream>
#include <type_traits>

// Wrapper #######################################

template<class T>
struct Wrapper {};

// All you need is a way to unwrap the T, right?

template<class T>
struct Unwrap { using type = T; };

template<class T>
struct Unwrap<Wrapper<T> > : Unwrap<T> {};

// Test function #######################################

void f(int) {
  std::cout<<"int"<<std::endl;
}

// Split unwrapping and checking it with enable_if<>:
template<class T,class U=typename Unwrap<T>::type>
auto f(T) -> 
  typename std::enable_if<
    std::is_same<int,U>::value
  >::type
{
  std::cout<<"Wrapper<...<int>...>"<<std::endl;
  f(U());
}    

int main() {
  f(Wrapper<int>());  
  return 0; 
}
template<class T, class Enable=void>
struct WrapperTraits {};

template<class T>
struct WrapperTraits<T,typename std::enable_if<IsWrapper<T>::value>::type> {
  typedef typename GetRootType<T>::RootType RootType;
};
// Plain-vanilla implementation of void_t
template<class...> struct voider { using type = void; };
template<class...Ts>
using void_t = typename voider<Ts...>::type;

// WrapperTraits #######################################

// Wrapper types specialize WrappedType to expose the type they wrap;
// a type T is a wrapper type iff the type WrappedType<T>::type exists.
template<class> struct WrappedType {};

// GetRootType unwraps any and all layers of wrappers.
template<class T, class = void>
struct GetRootType {
  using type = T; // The root type of a non-WrappedType is that type itself.
};

// The root type of a WrappedType is the root type of the type that it wraps.
template<class T>
struct GetRootType<T, void_t<typename WrappedType<T>::type>> :
  GetRootType<typename WrappedType<T>::type> {};

// non-WrappedTypes have no wrapper traits.
template<class T, class = void>
struct WrapperTraits {};

// WrappedTypes have two associated types:
// * WrappedType, the type that is wrapped
// * RootType, the fully-unwrapped type inside a stack of wrappers.
template<class T>
struct WrapperTraits<T, void_t<typename WrappedType<T>::type>> {
  using WrappedType = typename ::WrappedType<T>::type;
  using RootType = typename GetRootType<T>::type;
};

// Convenience aliases for accessing WrapperTraits
template<class T>
using WrapperWrappedType = typename WrapperTraits<T>::WrappedType;
template<class T>
using WrapperRootType = typename WrapperTraits<T>::RootType;


// Some wrappers #######################################

// Wrapper<T> is a WrappedType
template<class> struct Wrapper {};
template<class T>
struct WrappedType<Wrapper<T>> {
  using type = T;
};

// A single-element array is a WrappedType
template<class T>
struct WrappedType<T[1]> {
  using type = T;
};

// A single-element tuple is a WrappedType
template<class T>
struct WrappedType<std::tuple<T>> {
  using type = T;
};