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

Disable construction of non fully specialized template class

本文关键字:专用      更新时间:2023-10-16

我有这种模板类的结构。

我的目的是禁止创建那些不提供完整专业化的类:

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

一切都很好

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>());

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

这似乎是C++最烦人的解析问题:

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

这实际上只是一个函数声明:它声明一个返回Container<int>对象的函数a,并获取指向返回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{};

然后,在类模板的定义中放置一个使用此deferred_false<T>::valuestatic_assert

template<class T>
class Container final : public AbstractContainer
{
static_assert(deferred_false<T>::value, "Trying to instantiate Container<>");
};

这样,当要实例化Container的主模板时,断言将在编译时失败,但在主模板未实例化时不会失败,因为static_assert的条件取决于模板参数(即:T)。

也就是说,如果没有针对FooContainer专业化,并且您有:

Container<Foo> a;

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

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