替换enable_if以仅为一个模板值启用方法

时间:2017-10-26 21:24:26

标签: c++ visual-studio c++11 templates sfinae

我想让模板类限制一个像这个例子的重载方法:

template<int N>
class foo {
  public:
    void add(int a, int* b) {*b = a + N;} 
    int add(std::enable_if<N == 0, int> a, int b) {return a + b}
}

(更改示例以反映原始示例中不存在的并发症。)

但是,我使用的是Visual Studio,它对SFINAE(以及enable_if)的支持仍然不是很好。 (我不确定它是否适用于这个简单的例子;在我的实际情况中,我在类引用上使用std::enable_if并使用该类的成员,但它不起作用。)答案to this(我得到的错误消息基本上相同)建议使用标签调度作为替代方案,但我不确定如果我希望函数根本不可用那些参数类型那会怎样,或者如果我想以这种方式重载构造函数。

3 个答案:

答案 0 :(得分:3)

需要将其制作成功能模板。并且enable_if中的条件需要依赖于函数模板的模板参数,以便它不会被提前替换。

template<int M = N, 
         class = typename std::enable_if<M == 0>::type>
int add(int a, int b) { return a + b; }

答案 1 :(得分:0)

通常我会看到std::enable_if与返回类型

一起使用
template<int N>
class foo {
  public:
    int add(int a) 
     {return a + N;} 

    template <int M = N>
    typename std::enable_if<M == 0, int>::type add(int a, int b)
     {return a + b}
}

这没有用?

另一种方法可以是使用仅定义bar的基类(add(int, int),仅在所需的专门化中)。

template <int N>
struct bar
 { int add (int a, int b) = delete; };

template <>
struct bar<0>
 { int add (int a, int b) { return a + b; } };

template <int N>
struct foo : public bar<N>
 { using bar<N>::add; void add (int a, int * b) { *b = a + N; } };

int main()
 {
   foo<0>  f0;
   foo<1>  f1;

   int b { 0 };

   f0.add(1, &b);
   f0.add(1, 2);

   f1.add(1, &b);
   //f1.add(1, 2); // compilation error
 }

请注意using bar<N>::add中的foo是必需的,否则add(int) foo会隐藏add(int, int)中的bar。< / p>

usingint add (int a, int b) = delete;强加于bar<N>的通用版本。

如果两个函数的名称不同,对于包含2个整数参数的版本,请说add2(),示例变为如下

template <int N>
struct bar
 { };

template <>
struct bar<0>
 { int add2 (int a, int b) { return a + b; } };

template <int N>
struct foo : public bar<N>
 { void add (int a, int * b) { *b = a + N; } };

int main()
 {
   foo<0>  f0;
   foo<1>  f1;

   int b { 0 };

   f0.add(1, &b);
   f0.add2(1, 2);

   f1.add(1, &b);
   //f1.add2(1, 2); // compilation error
 }

答案 2 :(得分:0)

没有简单的代码转换是合法的。模板类的方法签名必须合法。

template<class D, bool> // false case
struct add_base {
  void add(int* a, int b) {*a += b}      
  D*self(){return static_cast<D*>(this);}
  D const*self()const{return static_cast<D const*>(this);}
};
template<class D>
struct add_base<D,true>:add_base<D,false> {
  using base=add_base<D,false>;
  using base::self;
  using base::add; // for overload resolution
  int add(int a, int b) {return a + b}
};

template<int N>
class foo: add_base<foo<N>, N==0> {
  using base = add_base<foo<N>, N==0>;
  template<class D, bool b>
  friend class add_base<D, b>;// may be a syntax error here.
public:
  using base::add;
};

这里我假设真正的add想要使用this;在这种情况下,在其实现中使用self()

还有其他技术使用带有默认值的模板参数,但是在严格阅读标准下它们的合法性是值得怀疑的。问题在于标准要求所有模板函数都具有有效的特化,并且大多数这些技术都违反了该规则。对于它们可能合法的标准有不同的读数。

您还可以等待个概念。