推断非类型模板参数的类型

Infer type of non-type template argument

我不擅长模板元编程,如果这是一个愚蠢的问题,我深表歉意。

我有这样的类型

template<int n>
struct S
{
  typedef decltype(n) type_of_n;

  // ...
};

我想编写类似于

的函数
template<
  typename T, 
  typename T::type_of_n n,
  typename = std::enable_if_t<std::is_same<T, S<n>>::value>>
void f(const T &) { /* ... */ }

的想法是,如果 S 的非类型模板参数的类型在将来的某个时候发生变化(比如 std::size_tint64_t 或其他),那么调用代码将继续工作。但是我不确定如何让编译器在这里同时推断出 Tn

我唯一想到的基​​本上都是黑客:

我想做的事情可行吗?如果没有,是否有比上面的 hack 更“干净”的方法?

if the type of the non-type template argument to S changes at some point in the future (say to std::size_t or int64_t or something) then calling code will just continue working.

您可以在 C++17 中使用 占位符类型 auto,如下所示:

template<auto n>  //note the auto here
struct S
{
  typedef decltype(n) type_of_n;

  // ...
};

你可以做一个特征来知道一个类型是否是 S<n>:

template <typename T>
struct is_a_S : std::false_type {};

template <int N>
struct is_a_S<S<N>> : std::true_type {};

那你的SFINAE就可以这样搞了:

template<
  typename T, 
  std::enable_if_t<is_a_S<T>::value, int> = 0>
void f(const T &) { /* ... */ }

C++20 概念让事情变得更简单

#include <concepts>

template<int n>
struct S {
  typedef decltype(n) type_of_n;
};

template<class T>
  requires std::same_as<T, S<typename T::type_of_n{}>>
void f(const T &) { /* ... */ }

Demo

如果您只想接受 S 并且还想推导 n 的值,那么您可以从 c++17 开始使用 auto 来推导 auto 的类型non-type 模板参数。

template<auto n>
void f(const S<n> &) { /* ... */ }

您还可以使其更通用,并通过使用模板模板参数接受具有单个 non-type 参数的任何类型。

template<template <auto> typename T, auto n>
void f(const T<n> &) { /* ... */ }