禁用非完全专用模板类的构造

时间:2018-03-16 08:13:30

标签: c++ c++11 templates default-constructor most-vexing-parse

我有一种模板类的结构。

我的目标是禁止创建那些没有完全专业化的课程:

class AbstractContainer
{
public:
   virtual ~AbstractContainer() = default;

   // declare here interface methods
};

template <class T>
class Container final : public AbstractContainer
{
public:
   Container() = delete;
};


template <>
class Container<int> : public AbstractContainer
{
public:
   Container() = default;

   explicit Container(const int& type) : AbstractContainer(), type_(type){}

private:
   int type_;
};

Everyhthing工作正常

Container<int> a;     // it works
Container<int> a(5);  // it works
Container<char> a;    // does not compile

但我注意到它编译了这些案例

Container<int> a(Container<char>());
Container<int> a(Container<CustomClass>());

我该如何避免这种情况?我确实想要一个复制构造函数,但没有错误的类型,理想情况下我想有相同的编译错误问题(我可以在某处使用断言,但不知道如何设置它)。

1 个答案:

答案 0 :(得分:2)

这似乎是C++'s most vexing parse问题:

Container<int> a(Container<char>());

这实际上只是一个函数声明:它声明了一个函数a,它返回一个Container<int>对象,并获取一个指向函数的指针,该函数返回Container<char>并且不执行任何操作。

由于它只是一个函数声明,它根本不会实例化Container<char>,因此您不会收到任何错误。

您可以使用大括号语法而不是括号,即:

Container<int> a{Container<char>()};
Container<int> b(Container<char>{});
Container<int> c{Container<char>{}};

上面的代码确实声明了三个对象:abc

在实例化Container<>的主要模板

时出现自定义错误

您可以将以下模板deferred_false定义为:

template<typename>
struct deferred_false {
    static constexpr auto value = false;
};

或简单地说:

#include <type_traits>
template<typename> struct deferred_false: std::false_type{};

然后,在您的班级模板定义中放置一个使用此static_assert的{​​{1}}:

deferred_false<T>::value

这样,当template<class T> class Container final : public AbstractContainer { static_assert(deferred_false<T>::value, "Trying to instantiate Container<>"); }; 的主模板将被实例化时,断言将在编译时失败,但是当主模板未被实例化时,断言将失败,因为条件是Container取决于模板参数(即:static_assert)。

也就是说,如果T没有Container的专业化,那么您有:

Foo

您将收到以下编译时错误:

  

错误:静态断言失败:尝试实例化Container<Foo> a;