繁体   English   中英

如果vector是特定长度,则使用C ++ 11 std :: enable_if启用成员函数

[英]Using C++11 std::enable_if to enable member function if vector is specific length

我正在编写一个简单的向量类,我希望有一些成员函数只能在某些长度的向量中使用(例如,3元素向量的交叉乘积)。 我偶然发现了std :: enable_if,看起来它可能能够做我想要的,但我似乎无法让它正常工作。

#include <iostream>
#include <type_traits>

template<typename T, unsigned int L>
class Vector
{
    private:
        T data[L];

    public:
        Vector<T,L>(void)
        {
            for(unsigned int i = 0; i < L; i++)
            {
                data[i] = 0;
            }
        }

        T operator()(const unsigned int i) const
        {
            return data[i];
        }

        T& operator()(const unsigned int i)
        {
            return data[i];
        }

        Vector<typename std::enable_if<L==3, T>::type, L> cross(const Vector<T,L>& vec2) const
        {
            Vector<T,L> result;

            result(0) = (*this)(1) * vec2(2) - (*this)(2) * vec2(1);
            result(1) = (*this)(2) * vec2(0) - (*this)(0) * vec2(2);
            result(2) = (*this)(0) * vec2(1) - (*this)(1) * vec2(0);

            return result;
        }
}; 

int main(void)
{
    Vector<double,3> v1;
    Vector<double,3> v2;
    Vector<double,3> v3;
    //Vector<double,4> v4;

    v1(0) = 1;
    v1(1) = 2;
    v1(2) = 3;

    v2(0) = 4;
    v2(1) = 5;
    v2(2) = 6;

    v3 = v1.cross(v2);

    std::cout << v3(0) << std::endl;
    std::cout << v3(1) << std::endl;
    std::cout << v3(2) << std::endl;

    return 0;
}

上面的代码编译并正确运行,但是如果我取消注释Vector<double,4> v4的声明,我在编译时会收到以下错误:

vec.cpp: In instantiation of ‘class Vector<double, 4u>’:
vec.cpp:46:22:   required from here
vec.cpp:29:59: error: no type named ‘type’ in ‘struct std::enable_if<false, double>’

有人能够指出我哪里出错吗?

 template<unsigned LL = L>
  Vector<typename std::enable_if<LL==3 && L == 3, T>::type, LL>
  cross(const Vector<T,LL>& vec2) const
  {
    Vector<T,L> result;

    result(0) = (*this)(1) * vec2(2) - (*this)(2) * vec2(1);
    result(1) = (*this)(2) * vec2(0) - (*this)(0) * vec2(2);
    result(2) = (*this)(0) * vec2(1) - (*this)(1) * vec2(0);

    return result;
  }

PS。 为什么这样工作?

变量v4的定义导致类模板Vector的隐式实例化,这反过来导致类成员函数声明的隐式实例化(14.7.1隐式实例化[temp.inst]#1)。 当然,后一种实例化会导致错误。

如果我们改为将成员函数更改为成员模板,则根据相同的子句,此时成员模板本身将被实例化,并且此实例化或多或少地看起来像:

template<unsigned LL = 3>
Vector<typename std::enable_if<LL==3 && 3 == 3, double>::type, LL>
cross(const Vector<double,LL>& vec2) const;

这是一个完全有效的模板声明。 此时我们不(并且我们不能)执行任何进一步的实例化。

但是,当我们尝试实际调用cross ,毫无疑问,这是“需要成员/函数定义存在的上下文”,因此,根据(14.7.1隐式实例化[temp.inst]#2,#3) , cross模板(第二个cross模板,即外部类模板实例化的结果)被隐式实例化,并且std::enable_if有机会完成其工作。 作为旁注,这是SFINAE原则适用的情况。

PPS。 为了进一步阐述,虽然没有与OP问题直接相关,但仍然值得一提的是,并不总是需要将成员声明为模板以便处理类似的情况。

在某些情况下,类模板的成员对于给定的实例化不是“有效”,但仍可以实例化类模板,例如:

#include <type_traits>

template<typename T>
struct S
{
  T x;

  T foo () const { return x; }

  typename std::remove_pointer<T>::type bar () const { return *x; }
};

S<int> x;
S<int *> y;

显然,在实例化S<int> ,表达式*x无效,因为x的类型是int 不过,这个程序是正确的。 重要的一点是,在隐式实例化期间,只实例化成员的声明 在上面的例子中,实例化S<int>导致声明 int bar() const; 要实例化,这是一个完全正确的声明。

当然,如果我们稍后尝试实例化S<int>::bar定义 ,就像在:

void f()
{
  x.foo ();
  //  x.bar (); // error
  y.foo ();
  y.bar ();
}

我们会收到一个错误。

(这仍然遵循上述C ++标准的两段)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM