如果存在从“double”到“T”的转换,SFINAE 禁用构造函数

SFINAE disable constructor if conversion exists from `double` to `T`

以下是我能想出的最小有意义的程序来重现我对这个问题的困境。由于 LinearForm<double> 的构造函数之间存在冲突,程序无法编译。为了解决这个冲突,当且仅当不存在从 doubleV 的转换时,我想启用 LinearForm<V>::LinearForm(double)。我怎样才能做到这一点? (它会解决构造函数之间的冲突吗?)

#include <type_traits>
#include <array>

template<int N>
struct Vector{
    std::array<double,N> coords;

    Vector(std::array<double,N> coords) : coords(coords) {}

    // implicit conversions between scalar and Vector<1>
    template<int Nd = N, std::enable_if_t<Nd==1>>
    Vector(double scalar) : coords(scalar) {}
    template<int Nd = N, std::enable_if_t<Nd==1>>
    operator double() const {return coords[0];}

    double dot(Vector<N> u) const {
        double acc = 0;
        for(int i=0; i<N; i++){
            acc += coords[i]*u.coords[i];
        }
        return acc;
    }

    static Vector<N> zero(){ return Vector<N>(std::array<double,N>{}); }
};

template<typename V> // V is domain element type i.e. LinearForm maps from V to double
struct LinearForm {
    V v;
    LinearForm(V v) : v(v) {}

    //template<typename Vd=V, typename = std::enable_if_t</* WHAT TO PUT IN HERE */>>
    LinearForm(double v) : LinearForm(V::zero())
    {
        if(v != 0){
            throw std::runtime_error("LinearForm cannot be non-zero constant.");
        }
    }
    double operator()(V u){return u.dot(v);}
};

int main()
{
    LinearForm<Vector<2>> lf(Vector<2>({1,2}));
    LinearForm<Vector<2>> zf = 0;

    LinearForm<double> slf = 0;

    auto u = Vector<2>({3,4});
    lf(u); // returns some value
    zf(u); // should return zero for any u

    return 0;
}

您可能想要使用 std::is_convertible。然后,这将完成工作:

template <typename Vd=V,
          typename std::enable_if_t<std::is_convertible<double, Vd>::value>::type* = nullptr>
LinearForm(double v) : LinearForm(V::zero())
{
    if(v != 0){
        throw std::runtime_error("LinearForm cannot be non-zero constant.");
    }
}

为了编译您的代码,我需要再添加两件事:

LinearForm(int value) : v(value) {}

并修改

template<int Nd = N, std::enable_if_t<Nd==1>>
Vector(double scalar) : coords(scalar) {}

template<int Nd = N>
Vector(double scalar) : coords({scalar}) {}

Live example

std::enable_if_t<std::is_convertible_v<double, Ty>>* = nullptr>

是您要搜索的内容