是否有可能使模板专用化基于方法签名中某个参数的存在或不存在? [英] Is it possible to base the template specialization on the presence or absence of a certain argument in the method signature?

查看:125
本文介绍了是否有可能使模板专用化基于方法签名中某个参数的存在或不存在?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

考虑下面的类:

class MyClass
{
public:
  template<class T> typename T::result_type apply(T& func)
  {
    if (is_int())
    {
      return func(int(0));
    }
    return func(double(0));
  }
  ...
};

(代码看起来不太有用,但它只是一个用来演示我的观点的示例)

(The code does not look terribly useful, but it is only a contrived sample to demonstrate my point)

无论如何,一个典型的函子是这样的:

Anyway, a typical functor would be something like this:

struct MyFunc
{
  typedef void result_type;
  template<class V> void operator()(V)
  {
    // do something
  }
};

而且会像这样使用:

MyClass c;
MyFunc f;
c.apply(f);

我的问题是这个 - 可以 MyClass :: apply 更改为识别除原始函数之外的函数稍有不同的版本,例如希望调用对象引用与所有其他参数一起传递的函数,如下所示:

My question is this - can MyClass::apply be changed to recognize a slightly different version of the functor in addition to the original one, for instance the one expecting the caller object reference to be passed along with all the other parameters, something like this:

struct MyFuncEx
{
  typedef void result_type;
  template<class V> void operator()(const MyClass& caller, V)
  {
    // do something
  }
};

因此,以下代码也会编译:

So, the following code would compile too:

MyClass c;
MyFunc f;
c.apply(f);
MyFuncEx f2;
c.apply(f2);

作为一个奖励,如果函子包含两个重载,我想编译失败,失败的编译:

As a bonus I would like the compilation to fail if the functor contains both overloads, i.e. the following should fail the compilation:

struct MyFuncSmartAss
{
  typedef void result_type;
  template<class V> void operator()(V)
  {
    // do something
  }
  template<class V> void operator()(const MyClass& caller, V)
  {
    // do something
  }
};

...

MyClass c;
c.apply(MyFuncSmartAss());

但是,并不重要,只要较长的重载优先于较短的重载。

But, it is not that important as long as the longer overload takes the precedence over the shorter one.

推荐答案

这取决于你是否有C ++ 11。此应该解决C ++ 11(*)中的超载问题:

It really depends whether you have C++11 or not. This should solve the overload issue in C++11 (*):

class MyClass {
private:
  int _int;
  double _double;

public:
  template <typename F>
  auto apply(F& f) -> decltype(f(_int), f(_double)) {
    if (is_int()) { return f(_int); }
    return f(_double);
  }

  template <typename F>
  auto apply(F& f) -> decltype(f(*this, _int), f(*this, _double)) {
    if (is_int()) { return f(*this, _double); }
    return f(_double)
  }

};

它是如何工作的?


  • 删除不适当的重载:使用 decltype 的尾随返回类型规范创建了一个未评估的上下文。编译器执行表达式的常规重载解析,但只关心类型。如果发生错误( operator()不存在于 f 中),那么我们命中SFINAE, apply 被丢弃

  • 模糊性如果两者都工作:如果两个重载都合适(因为 F 提供两个运算符)然后调用是不明确的

  • Removing unsuitable overloads: the trailing-return-type specification with decltype creates an unevaluated context. The compiler performs regular overload resolution of the expression but only cares about the type. If an error occurs (the operator() does not exist in f), then we hit SFINAE and this overload of apply is discarded
  • Ambiguity if both work: if both overloads are suitable (because F provides both operators) then the call is ambiguous

(*)我不太确定拖尾的正确性,返回类型规范,更具体地使用 this _arg 。 Clang 3.0和 gcc 4.5.2 错误。

(*) I am not too sure about the correctness of the trailing-return-type specification, and more specifically the use of this and _arg. Both Clang 3.0 and gcc 4.5.2 error out. This can be worked around, just get a bit more verbose.

// first
decltype(f(0), f(0.0))

// second
decltype(f(std::declval<MyClass>(), 0), f(std::declval<MyClass>(), 0.0))

使用此解决方法在ideone执行操作:

In action at ideone with this workaround:

  • No possible function.
  • Suitable overload is selected.
  • Ambiguous calls avoided.

以处理 int / double 需求。

这篇关于是否有可能使模板专用化基于方法签名中某个参数的存在或不存在?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆