【问题标题】:using SFINAE to change function called in a class depending on type of class template parameter使用 SFINAE 根据类模板参数的类型更改类中调用的函数
【发布时间】:2013-03-13 00:39:24
【问题描述】:

我有一个可以采用标量或索引类型的模板类,我想根据函数的类型调用不同版本的函数:

template <typename Ta, typename ... T>
struct MyClass {
    Ta tt; //can be either a scalar (double, complex<double>, int, etc), 
          //or an indexed type (MyClass, std::vector<double>, double[], etc)

    //....

    //I would like the following to be called when tt is a scalar type:
    auto operator[]( size_t i ) { return tt; };

    //I would like the following to be called when tt has [] overloaded:
    auto operator[]( size_t i ) { return tt[i]; };

};

有没有办法做到这一点?返回值 SFINAE 不起作用(因为此函数上没有模板参数),基于类的 SFINAE 似乎不起作用(因为可变参数模板使得最后有一个虚拟模板参数不起作用)。还有其他想法吗?

【问题讨论】:

  • 请注意,函数返回类型的“auto”在 C++1y 标准中。在 C++11 中,您应该使用如下语法:“auto operator[]( size_t i ) -> decltype(this->value(0, 0))”(如上面的答案中所述)

标签: c++ templates c++11 sfinae


【解决方案1】:

我相信 Xeo 误解了 Andrew 所说的“标量”的含义。 Xeo 遵循标量的 C/C++ 定义(根据 C++11、3.9/9),而 Andrew 的意思更接近线性代数意义(向量空间的基础字段的元素)。例如,虽然 Andrew std::complex&lt;double&gt; 是标量,但 Xeo 不是这种情况,因为他使用 std::is_scalar&lt;std::complex&lt;double&gt;&gt; 来检查它,当然,他得到了 false

我相信,Andrew 想要的是 operator[](size_t i) 返回:

  1. tt[i] 如果tt[i] 是合法的;或

  2. tt 如果tt[i] 是非法的。

我们可以轻松地将 SFINAE 淘汰掉上面的第一个候选人。通过实现一个检查调用 tt[i] 是否合法的特征,我们还可以在表达式合法时 SFINAE 离开第二个候选者。创建这个特征不是很简单,并且依赖于重载解决方案(真正的经典no f(...))。我将跳过特征的创建,而是直接在MyClass 中使用相同的想法。为避免使用虚拟参数污染operator[]() 的签名(重载解决技巧所需),我将创建名为value() 的私有方法,该方法采用虚拟参数。然后operator[]() 只会将调用委托给其中一个。

代码如下。

#include <type_traits> // for std::declval

template <typename Ta>
class MyClass {

    // This overload is SFINAEd away when tt[i] is illegal
    template <typename T = Ta, typename R = decltype(std::declval<T>()[0])>
    R
    value(size_t i, int) { return tt[i]; }

    // This one is always present but is a worse match than the other
    // one when resolving value(i, 0).
    const Ta&
    value(size_t, ...) { return tt; }

public:

    Ta tt;

    auto operator[]( size_t i ) -> decltype(this->value(0, 0)) {
        return value(i, 0);
    }

};

【讨论】:

  • 关于“标量”可能意味着什么的一个好点,+1。我也想过走“是tt[i]有效”的路线,但我懒得写你所拥有的。 :) 顺便说一句,this 你可能会感兴趣。
  • 谢谢!这确实是我感兴趣的。
【解决方案2】:

只需给operator[]s 一个虚拟模板参数即可。

template<class U = Ta, EnableIf<std::is_scalar<U>>...>
auto operator[]( size_t i ){ return tt; };

template<class U = Ta, DisableIf<std::is_scalar<U>>...>
auto operator[]( size_t i ) { return tt[i]; };

请参阅here 了解有关这种特殊 SFINAE 风格的一些解释。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-11-30
    • 2022-01-20
    • 2013-08-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-07-26
    相关资源
    最近更新 更多