禁用非完全专用模板的构建 class
Disable construction of non fully specialized template class
我有这样的模板结构class。
我的目标是禁止创建那些 class 不提供完整专业化的内容:
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++'s most vexing parse 问题:
Container<int> a(Container<char>());
这实际上只是一个函数声明:它声明了一个函数 a
returns 一个 Container<int>
对象并接受一个指向 returns Container<char>
什么都不拿。
因为它只是一个函数声明,它根本不会实例化 Container<char>
,因此您不会收到任何错误。
您可以使用大括号语法代替圆括号,即:
Container<int> a{Container<char>()};
Container<int> b(Container<char>{});
Container<int> c{Container<char>{}};
上面的代码确实声明了三个对象:a
、b
和 c
。
实例化 Container<>
的主模板时出现自定义错误
您可以将以下模板 deferred_false
定义为:
template<typename>
struct deferred_false {
static constexpr auto value = false;
};
或简称为:
#include <type_traits>
template<typename> struct deferred_false: std::false_type{};
然后,在 class 模板的定义中放置一个使用此 deferred_false<T>::value
的 static_assert
:
template<class T>
class Container final : public AbstractContainer
{
static_assert(deferred_false<T>::value, "Trying to instantiate Container<>");
};
这样,当 Container
的主模板将被实例化时,断言将在编译时失败,但当主模板未被实例化时,断言将不会失败,因为static_assert
取决于模板参数(即:T
)。
也就是说,如果 Foo
没有 Container
的特化并且您有:
Container<Foo> a;
您将收到以下 compile-time 错误:
error: static assertion failed: Trying to instantiate Container<>
我有这样的模板结构class。
我的目标是禁止创建那些 class 不提供完整专业化的内容:
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++'s most vexing parse 问题:
Container<int> a(Container<char>());
这实际上只是一个函数声明:它声明了一个函数 a
returns 一个 Container<int>
对象并接受一个指向 returns Container<char>
什么都不拿。
因为它只是一个函数声明,它根本不会实例化 Container<char>
,因此您不会收到任何错误。
您可以使用大括号语法代替圆括号,即:
Container<int> a{Container<char>()};
Container<int> b(Container<char>{});
Container<int> c{Container<char>{}};
上面的代码确实声明了三个对象:a
、b
和 c
。
实例化 Container<>
的主模板时出现自定义错误
您可以将以下模板 deferred_false
定义为:
template<typename>
struct deferred_false {
static constexpr auto value = false;
};
或简称为:
#include <type_traits>
template<typename> struct deferred_false: std::false_type{};
然后,在 class 模板的定义中放置一个使用此 deferred_false<T>::value
的 static_assert
:
template<class T>
class Container final : public AbstractContainer
{
static_assert(deferred_false<T>::value, "Trying to instantiate Container<>");
};
这样,当 Container
的主模板将被实例化时,断言将在编译时失败,但当主模板未被实例化时,断言将不会失败,因为static_assert
取决于模板参数(即:T
)。
也就是说,如果 Foo
没有 Container
的特化并且您有:
Container<Foo> a;
您将收到以下 compile-time 错误:
error: static assertion failed: Trying to instantiate
Container<>