模板化构造函数匹配比模板化类型转换更好

时间:2016-04-01 18:49:54

标签: c++ c++11

以下编译正常:

#include <iostream>
#include <vector>

class Point : public std::vector<double>
{
public:
    Point() = default;
};

class MyClass
{
public:

    template <typename T>
    operator T() const { return T(); }
};

int main()
{
    MyClass myClass;
    Point test = myClass;

    return 0;
}

但是,如果我有一个模板化的构造函数,它不会:

#include <iostream>
#include <vector>

class Point : public std::vector<double>
{
public:
    Point() = default;

    template <typename TVector>
    Point(const TVector& v)
    {
        (*this)[0] = v[0]; // compiler error on this line (saying no operator[] for MyClass, but the point is that this function is used instead of the type conversion function)
    }

};

class MyClass
{
public:

    template <typename T>
    operator T() const { return T(); }
};

int main()
{
    MyClass myClass;
    Point test = myClass;

    return 0;
}

我无法更改Point类(添加第二个默认构造函数参数或类似的东西),那么有没有办法只更改MyClass以使其工作?

2 个答案:

答案 0 :(得分:1)

operator[]

中没有TVector时,您可以使用SFINAE禁用构造函数
template <typename TVector, typename=decltype(std::declval<const TVector&>()[0])>
Point(const TVector& v)

当尝试评估第二个typename时,编译器必须推断出TVector::operator[]返回的内容。当它不能时,它会从重载决策中抛出构造函数。

如果您想稍微详细说明,可以使用enable_ifPoint

中更明确地看一下
template <typename...>
using void_t = void;

template <typename T, typename = void>
struct HasIndexOperator : std::false_type {};

template <typename T>
struct HasIndexOperator<T,
          void_t<decltype(std::declval<const T&>()[0])>> : std::true_type {};

然后你的构造函数变为:

template <typename TVector, 
          typename=std::enable_if_t<HasIndexOperator<TVector>{}>>
      Point(const TVector& v)

答案 1 :(得分:-1)

像这样的模板构造函数

template <typename TVector>
    Point(const TVector& v)

将作为用户定义的构造函数工作,接受任何不属于Point类型的东西(仍然由隐含定义的复制构造函数处理)。

Point point = myclass;

编译器正在查找模板化构造函数,不执行任何转换并尝试在operator[]上调用MyClass

当您为非向量禁用模板化构造函数(如Ryan所建议)时,唯一剩下的就是非模板复制构造函数,隐含地声明为

Point(const Point& );

编译器将执行从MyClassPoint的转换,一切都将编译。