【问题标题】:Disable construction of non fully specialized template class禁用非完全专业化模板类的构建
【发布时间】:2018-08-25 05:37:27
【问题描述】:

我有这样的模板类结构。

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

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

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

【问题讨论】:

  • 这引出了一个问题,为什么有一个默认模板?
  • @StoryTeller 你的意思是为什么不直接删除默认模板或者为什么不使用没有模板的继承?
  • 后者。您实质上是在这里定义整个类。甚至不要使用主节点可以提供的“默认实现”
  • @StoryTeller 我可能想在未来使用和管理默认实现并保持打开大门
  • 普通班也关不上门。但没关系,这是您的代码库。你可能比我有更清晰的观点。

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


【解决方案1】:

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

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

这实际上只是一个函数声明:它声明了一个函数 a,它返回一个 Container&lt;int&gt; 对象,并接受一个指向返回 Container&lt;char&gt; 的函数的指针,并且什么都不接受。

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

您可以使用大括号语法代替括号,即:

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

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


实例化Container&lt;&gt; 的主模板时出现自定义错误

您可以将以下模板 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&lt;T&gt;::valuestatic_assert

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;

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

错误:静态断言失败:尝试实例化Container&lt;&gt;

【讨论】:

  • 您可以使用template &lt;typename&gt; struct deferred_false : std::false_type {};
  • deferred_false必须是模板函数吗?
  • @Moia 是的,否则它会使程序非法,不需要诊断
  • 是的,false 的评估必须推迟到主模板实例化,否则即使您不实例化模板,static_assert 也会失败。
猜你喜欢
  • 1970-01-01
  • 2011-01-18
  • 1970-01-01
  • 1970-01-01
  • 2023-03-28
  • 2018-09-28
  • 1970-01-01
  • 2016-11-09
  • 1970-01-01
相关资源
最近更新 更多