在 C++14 中将模板参数限制为类的最佳方法是什么?

问题描述 投票:0回答:1

我的结构如下:

template <typename Arg1, typename Arg2>
class TemplateClass { ... };

template <typename TClass>
class UsesTemplateClass {
public:
    UsesTemplateClass( TClass& instance ) inst{instance} { ... }
private:
    TClass& inst;
};

template <typename TClass>
auto make_uses_template_class( TClass& instance ) {
    return UsesTemplateClass<TClass>{ instance };
}

make_uses_template_class
存在的原因是函数模板可以推导类型,因此用户客户端不必显式指定它。我意识到 C++17 和 C++20 对于此类事情有更好的语法,但我需要使用 C++14。

只要传入

make_uses_template_class
的类型确实是
TemplateClass
的实例化,就可以正常工作,但如果不是,结果将是
UsesTemplateClass
内部出现一些可怕的错误。

我想做的是,如果

make_template_class
不是
TClass
,则确保不存在
TemplateClass
重载。另外,如果有人尝试使用不是
UsesTemplateClass
的参数手动实例化
TemplateClass
,我希望错误消息是合理的。

我知道有多种方法可以做到这一点,但我没有看到很多关于如何在这种情况下使用启用程序或 static_asserts 的一致指导。

例如,关于课程,我想我可以做这样的事情:

template <typename TClass>
class UsesTemplateClass;  // declared but not defined

template <typename Arg1, typename Arg2>
class UsesTemplateClass<Arg1, Arg2> {
   // real definition
};

这会起作用(如果你用

TemplateClass
以外的任何东西实例化它,它会抱怨
UsesTemplateClass<SomeOtherType>
不存在)。我对必须在我的专业化中显式指定
TemplateClass
的参数感到不高兴,因为在一般情况下,可能有几个模板参数可能会发生变化。

或者,我有一个想法,将

using template_class_tag = void
之类的东西放入
TemplateClass
中,然后将
UsesTemplateClass
定义为:

template <typename TClass,
          typename = typename TClass::template_class_tag >
class UsesTemplateClass { ... };

但我在几个线程中看到,对类使用这种类型的启用器通常不受欢迎,并且通常建议使用

static_assert
。据我所知,普遍的共识是
static_assert
可以提供更好的错误消息,并且它不会像用户为默认模板参数指定类型那样被滥用。不幸的是,我不相信可以编写一个静态断言来判断 TClass::template_class_tag 类型是否存在。

为了解决这个问题,我想我可以给

TemplateClass
一个非模板库,并使用
std::is_base_of
的静态断言。我认为这会起作用,尽管它有点侵入性(基类没有其他目的)。

是否有一个普遍接受的习惯用法来以这种方式限制像

UsesTemplateClass
这样的类?

该函数也有同样的问题,但我知道启用器等在函数中的使用方式通常与在类中不同,所以我也想问一下。

c++ templates c++14
1个回答
0
投票

我想做的是确保如果 TClass 不是 TemplateClass,则 make_template_class 重载不存在。另外,如果有人尝试使用不是 TemplateClass 的参数手动实例化 UsesTemplateClass,我希望错误消息是合理的。

一个简单的解决方案是将模板定义更改为:

template <typename T1, typename T2>
class UsesTemplateClass {
public:
    UsesTemplateClass( TemplateClass<T1, T2>& instance ) inst{instance} {}
private:
    TemplateClass<T1, T2>& inst;
};

template <typename T1, typename T2>
auto make_uses_template_class( TemplateClass<T1, T2>& instance ) {
    return UsesTemplateClass<T1, T2>{ instance };
}

进行此更改后,以下内容将起作用:

auto a = make_uses_template_class(TemplateClass<int, double>());
auto b = UsesTemplateClass<int, double>(TemplateClass<int, double>());

但是以下会导致编译器错误:

auto a = make_uses_template_class(10);
auto b = UsesTemplateClass<int>(0);
© www.soinside.com 2019 - 2024. All rights reserved.