1

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

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 似乎不起作用(因为可变参数模板使得最后有一个虚拟模板参数不起作用)。还有其他想法吗?

4

2 回答 2

4

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

我相信,安德鲁想要的是operator[](size_t i)回归:

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

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

我们可以轻松地将 SFINAE 排除在上面的第一个候选者之外。通过实现一个检查调用tt[i]是否合法的特征,我们还可以在表达式合法时 SFINAE 离开第二个候选者。创建这个特征不是很简单,并且依赖于重载决议(真正的经典no f(...))。我将跳过 trait 的创建,而是直接在内部使用相同的想法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);
    }

};
于 2013-03-12T16:31:15.223 回答
3

只需给出operator[]sa 虚拟模板参数即可。

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]; };

有关这种特殊风格的 SFINAE 的一些解释,请参见此处

于 2013-03-12T01:48:51.827 回答