c++ - 是否可以根据方法签名中某个参数的存在或不存在来进行模板特化?

标签 c++

考虑以下类:

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

(代码看起来不是很有用,但它只是一个人为的例子来证明我的观点)

无论如何,一个典型的仿函数应该是这样的:

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

人们会这样使用它:

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

我的问题是 - MyClass::apply 是否可以更改以识别一个略微不同的仿函数版本除了原始版本,例如期望的版本要与所有其他参数一起传递的调用者对象引用,如下所示:

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

所以,下面的代码也可以编译:

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

作为奖励,如果仿函数包含两个重载,我希望编译失败,即以下应该编译失败:

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());

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

最佳答案

这真的取决于你是否拥有 C++11。这应该解决 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 提供了两个运算符)那么调用就是有歧义的

(*) 我不太确定尾随返回类型规范的正确性,更具体地说,this_arg 的使用。 Clang 3.0 和 gcc 4.5.2出错了。这可以解决,只是更冗长一点。

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

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

在 ideone 中使用此变通方法:

编辑:应对 int/double 要求。

关于c++ - 是否可以根据方法签名中某个参数的存在或不存在来进行模板特化?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9017139/

相关文章:

c++ - 如何正确使用vector<uint8_t>.data()?

C++ vector 丢失指针引用

c++ - 使用新的控制台窗口创建进程,但覆盖一些标准的 i/o 句柄

c++ - 捕获所有错误

c++ - 如何使用 new 过度分配内存以在结构中分配变量?

c++ - 了解 vtu 文件大小

尝试 'rewrite' 字符数组的 C++ 错误

c++ - 防止 C++ 中的多重继承

c++ - 大量 sp_counted_impl_p 对象

c++ - 使用 boost::lambda::bind 有什么问题?