C++ 可以推断非类型模板参数的类型并强制其余模板参数的类型吗?

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

考虑这个结构。它是一个范围,但使用模板而不是构造函数,使值静态:

template <int min_v, int max_v>
struct num_range final {
  constexpr static int min = min_v;
  constexpr static int max = max_v;
}
// now you can do
std::cout << num_range<1,3>::min << '\n'; // prints 1

但这被固定为

int
。如果我希望 C++ 从第一个参数推导数字类型并将其强制应用于第二个参数怎么办?

我试过这个:

template <typename TNumber>
template <TNumber min_v, TNumber max_v>
struct num_range final 

我按照相反的顺序尝试了。我知道你可以做到这一点:

template <auto min_v, decltype(min_v) max_v>
struct num_range final {
    using num_type = decltype(min_v);
    constexpr static num_type min = min_v;
    constexpr static num_type max = max_v;
};

但我认为 C++17 中不允许使用

auto
模板参数,这正是我的目标。它似乎也没有强制第二个模板参数的类型,因为这编译得很好:

std::cout << num_range<-10, 12U>::min << '\n'; // prints -10

如果您知道如何使用可变模板执行此操作,强制所有数字为同一类型,则会加分。

c++ templates c++17 auto non-type-template-parameter
2个回答
2
投票

我认为 C++17 中不允许使用自动模板参数

C++17 中允许。

它似乎也没有强制第二个模板参数的类型

是的,传递模板参数时允许进行一些隐式转换。改为这样做:

template <auto min_v, auto max_v>
struct num_range
{
    static_assert(std::is_same_v<decltype(min_v), decltype(max_v)>);
    constexpr static auto min = min_v;
    constexpr static auto max = max_v;
};

或者在 C++20 中:

template <auto min_v, auto max_v>
requires std::is_same_v<std::is_same_v<decltype(min_v), decltype(max_v)>
struct num_range
{
    constexpr static auto min = min_v;
    constexpr static auto max = max_v;
};

2
投票

你原来的方法确实有效,只是你没有让它引人注目:

using range = num_range<static_cast<signed char>(0), 200>;

clang 拒绝这一点:

<source>:8:54: error: non-type template argument evaluates to 200, which cannot be narrowed to type 'decltype('\x00')' (aka 'signed char') [-Wc++11-narrowing]
    8 | using range = num_range<static_cast<signed char>(0), 200>;
      |   

在您的示例中

num_range<-10, 12U>
12U
可以转换为
int
-10
的类型),因此一切都可以正常编译。

诚然,这种行为令人惊讶,因为

-10
12U
仍然是不同的类型,并且
num_range<-10, 12U>
编译直观上是错误的,但隐式转换使其可以工作。如果你想防止这种情况,你需要分别推导这两种类型,然后检查它们是否相同(@HolyBlackCat为此提供了两种解决方案)。

但我认为 C++17 中不允许使用自动模板参数

是的,请参阅cppreference:模板参数

如果您知道如何使用可变模板执行此操作,强制所有数字为同一类型,则会加分。

template <auto Head, decltype(Head)... Tail>
/* ... */

或者,类似于@HolyBlackCat的解决方案,使用

std::enable_if

template <auto Head, auto... Tail, std::enable_if_t<(std::is_same_v<decltype(Head), decltype(Tail)> && ...), int> = 0>
/* ... */
© www.soinside.com 2019 - 2024. All rights reserved.