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
C++ 禁用模板类中的函数_C++_Templates - Fatal编程技术网

C++ 禁用模板类中的函数

C++ 禁用模板类中的函数,c++,templates,C++,Templates,我试图禁用一个简单模板类中的一些函数。应该删除的函数取决于模板参数是否具有某些typedef 这个例子可以归结为: template<typename T> struct Foo { typename T::Nested foo() { return typename T::Nested(); } int bar() { return 1; } }; struct NoNested { }; struct WithNested { typedef int Neste

我试图禁用一个简单模板类中的一些函数。应该删除的函数取决于模板参数是否具有某些typedef

这个例子可以归结为:

template<typename T>
struct Foo
{
  typename T::Nested foo() { return typename T::Nested(); }
  int bar() { return 1; }
};


struct NoNested
{
};

struct WithNested
{
  typedef int Nested;
};

int main()
{
  Foo<WithNested> fwn;
  fwn.foo();
  fwn.bar();

  Foo<NoNested> fnn;
  //fnn.foo();
  fnn.bar();
}
所以

FSM<StateA>().next().prev().next().next();
FSM().next().prev().next().next();
编译,但是

FSM<StateA>().next().prev().prev();
FSM().next().prev().prev();
失败了

请注意,实际上会有更多的转换函数,转换函数实际上会做一些事情,FSM会存储一些状态

更新: 我已经使用到目前为止给出的方法创建了。
答案在复杂性上各不相同,虽然visitors方法是我最终可能使用的方法(因为它最简单),但我的解决方案(最复杂)是唯一实际删除函数的方法。

您可以使用类模板专门化。如果您有多个函数,那么可以将每个函数移动到一个基类,并对每个基类进行专门化。

以下是我认为可以解决的方法。它的灵感来自user763305的评论。 它需要2*N的专业知识,而不是2^N

template <typename T>
struct has_nested {
  // Variables "yes" and "no" are guaranteed to have different sizes,
  // specifically sizeof(yes) == 1 and sizeof(no) == 2.
  typedef char yes[1];
  typedef char no[2];

  template <typename C>
    static yes& test(typename C::Nested*);

  template <typename>
    static no& test(...);

  // If the "sizeof" the result of calling test<T>(0) would be equal to the sizeof(yes),
  // the first overload worked and T has a nested type named type.
  static const bool value = sizeof(test<T>(0)) == sizeof(yes);
};



template<typename T>
struct FooBase
{
  int bar() { return 1; }
};

template<typename T, bool>
struct FooImpl : public FooBase<T>
{
};

template<typename T>
struct FooImpl<T,true> : public FooBase<T>
{
  typename T::Nested foo() { return typename T::Nested(); }
};


template<typename T>
struct Foo : public FooImpl<T, has_nested<T>::value >
{
};


struct NoNested
{
};

struct WithNested
{
  typedef int Nested;
};

int main()
{
  Foo<WithNested> fwn;
  fwn.foo();
  fwn.bar();

  Foo<NoNested> fnn;
  //fnn.foo();
  fnn.bar();

}
模板
结构已嵌套{
//变量“是”和“否”保证有不同的大小,
//具体地说,sizeof(yes)==1和sizeof(no)==2。
typedef char yes[1];
typedef字符编号[2];
模板
静态是&测试(typename C::Nested*);
模板
静态no&test(…);
//如果“sizeof”,则调用测试(0)的结果将等于sizeof(是),
//第一个重载起作用,T有一个名为type的嵌套类型。
静态常量布尔值=sizeof(测试(0))==sizeof(是);
};
模板
结构FooBase
{
int bar(){return 1;}
};
模板
struct FooImpl:公共FooBase
{
};
模板
struct FooImpl:公共FooBase
{
typename T::Nested foo(){返回typename T::Nested();}
};
模板
struct Foo:public FooImpl
{
};
结构未测试
{
};
嵌套结构
{
typedef int嵌套;
};
int main()
{
傅福文;
fwn.foo();
fwn.bar();
傅福宁;
//fnn.foo();
fnn.bar();
}

尝试制作函数
foo
模板本身。它只有在被调用时才会编译,因此只有当您尝试使用
NoNested
类调用它时才会出现错误。

您可以向每个类添加嵌套的typedef,这样,只有在实例化函数时编译才会失败

struct null_type;  //an incomplete type, you could use a more descriptive name for your particular problem

template<typename T>
struct Foo
{
  typename T::Nested foo() { return typename T::Nested(); }
  int bar() { return 1; }
};


struct NoNested
{
   typedef null_type Nested;
};

struct WithNested
{
  typedef int Nested;
};

int main()
{
  Foo<WithNested> fwn;
  fwn.foo();
  fwn.bar();

  Foo<NoNested> fnn;
  //fnn.foo();  //attempt to use incomplete type when used
  fnn.bar();
}
struct null\u类型//如果是不完整的类型,您可以为您的特定问题使用更具描述性的名称
模板
结构Foo
{
typename T::Nested foo(){返回typename T::Nested();}
int bar(){return 1;}
};
结构未测试
{
typedef null_类型嵌套;
};
嵌套结构
{
typedef int嵌套;
};
int main()
{
傅福文;
fwn.foo();
fwn.bar();
傅福宁;
//fnn.foo();//使用时尝试使用不完整类型
fnn.bar();
}

可以选择类型
T::Nested
(如果存在),否则
void
,如下所示

默认选择为
void

template<class T, class = void>
struct NestedReturn
{
  typedef void type;
};
SFINAE对嵌套类为
的类型的专门化。请注意,
typename Void::type
始终为Void,以匹配基本模板中的默认第二个参数
Void

template<class T>
struct NestedReturn<T, typename Void<typename T::Nested>::type>
{
  typedef typename T::Nested type;
};
我怀疑使用默认函数模板参数可以正确地使用SFINAE删除
foo()
,但这仅在C++11中是可能的(未经测试的猜测):

模板
结构Foo
{
模板
N foo(){return N();}
int bar(){return 1;}
};

“我正试图禁用一个简单模板类中的某些函数。”为什么?在您的解决方案中,您可以通过使用继承链而不是多重继承来删除虚拟继承。@ymett,同意,这是我第一次这么做的,但是在添加一些函数后,类开始变得非常笨拙,当您在每个继承级别获得一个模板参数时。每个模板只需要一个额外的参数,即下一个级别。除了最后的字符串
(编辑)我认为这不是他的意思。这不是有点太复杂了吗?您可以只在正确的模板专门化中添加所需的方法。问题仍然存在:您为什么要尝试这样做,您真正想用它解决什么问题(可能有比这种黑客更好的解决方案)
template<class T>
struct Void
{
  typedef void type;
};
template<class T>
struct NestedReturn<T, typename Void<typename T::Nested>::type>
{
  typedef typename T::Nested type;
};
template<typename T>
struct Foo
{
  typename NestedReturn<T>::type foo() { return typename T::Nested(); }
  int bar() { return 1; }
};


struct NoNested
{
};

struct WithNested
{
  typedef int Nested;
};

int main()
{
  Foo<WithNested> fwn;
  fwn.foo();
  fwn.bar();

  Foo<NoNested> fnn;
  //fnn.foo();
  fnn.bar();
}
template<typename T>
struct Foo
{
  template<class N = T::Nested>
  N foo() { return N(); }
  int bar() { return 1; }
};