继承标准库类型特征

Mor*_*enn 15 c++ type-traits c++11

在编写自定义类型特征时,我经常从标准库类型特征派生它们,如下所示:

template<typename T>
struct some_type_trait:
    std::is_arithmetic<T>
{};
Run Code Online (Sandbox Code Playgroud)

但是,我有时想知道继承type标准库类型特征的成员类型是否更清晰:

template<typename T>
struct some_type_trait:
    std::is_arithmetic<T>::type
{};
Run Code Online (Sandbox Code Playgroud)

总的想法是只有std::bool_constant最终事物的继承,但我们从std::is_arithmetic第一个例子继承而不是直接从std::bool_constant(如第二种情况)继承的事实可以通过多态或类似的实现来观察std::is_base_of.

要点是直接从bool_constantvia type成员类型继承感觉更干净,因为它正是我们想要的.但是,继承的std::is_arithmetic时间稍短,并提供基本相同的行为.那么......在挑选其中一个时,我可能会遗漏任何微妙的优势(正确性,编译时......)?std::is_arithmetic与直接从底层继承相比,是否存在继承可能会改变应用程序行为的微妙场景bool_constant

Yak*_*ont 3

第二个有一个小缺陷,即泄露实现细节;如果您继承is_arithmetic<int>或其他什么,有人可以通过函数重载进行测试。这可能会“起作用”并导致误报。

这是一个非常小的问题。

is_arithmetic如果编译器转储基类名称,则通过继承可能会获得更好的诊断结果。

你们的设计都不好。反而:

template<class T>
struct some_type_trait:
  std::integral_constant<bool,
    std::is_arithmetic<T>{}
  >
{};
Run Code Online (Sandbox Code Playgroud)

可以扩展,因为我们可以在其中放置任何表达式。

正如我之前指出的,在错误消息中包含类型会很有帮助,因此我们可以这样做:

constexpr bool all_of() { return true; }
template<class...Bools>
constexpr bool all_of(bool b0, Bools...bs) {
    return b0 && all_of(bs...);
}
template<class T, template<class...>class...Requirements>
struct Requires : std::integral_constant<bool,
  Requirements<T>{} &&...
  // in C++11/14, something like: all_of(Requirements<T>::value...)
> {};
Run Code Online (Sandbox Code Playgroud)

然后我们得到:

template<class T>
using some_type_trait = Requires<T, std::is_arithmetic>;
Run Code Online (Sandbox Code Playgroud)

如果它无法在标签调度中找到重载,则会生成一个错误,这可能会给您提供线索。

template<class T>
void test( std::true_type passes_test, T t ) {
  std::cout << t+0 << "\n";
}
template<class T>
void test(T t) {
  return test(some_type_trait<T>{}, t);
}
int main() {
  test(3);
  test("hello");
}
Run Code Online (Sandbox Code Playgroud)

遗憾的是,我们在模板元编程中没有相当于简单绑定/部分应用/柯里化的功能。所以f<.> = is_base_of<X, .>很难简洁地表达。

活生生的例子,我们得到的错误消息是:clang:

main.cpp:23:10: note: candidate function [with T = const char *] not viable: no known conversion from 'some_type_trait<const char *>' (aka 'Requires<const char *, std::is_arithmetic>') to 'std::true_type' (aka 'integral_constant<bool, true>') for 1st argument
Run Code Online (Sandbox Code Playgroud)

海湾合作委员会:

main.cpp:28:18: note:   cannot convert 'Requires<const char*, std::is_arithmetic>()' (type 'Requires<const char*, std::is_arithmetic>') to type 'std::true_type {aka std::integral_constant<bool, true>}'
Run Code Online (Sandbox Code Playgroud)

这至少会导致您出现错误(const char*不是is_arithmetic)。

  • 编译器不会假设它是该上下文中的值,因为它不能是值。因此,仅继承“is_arithmetic&lt;T&gt;::type”就可以了。不必要,但很好。 (3认同)