如何将无参数模板方法限制为自己模板类的类型



我有一个表示特殊整数类型的模板类。

这个类的一个最小实现可能是这样的:

template<typename T>
struct Int {
static_assert(std::is_integral_v<T>, "Requires integral type.");
using NT = T;
T v;
explicit constexpr Int(T v) noexcept : v{v} {}

template<typename U, std::enable_if_t<std::is_integral_v<U>, bool> = true>
constexpr auto cast() const noexcept -> Int<U> {
return Int<U>{static_cast<U>(v)};
}

template<typename U, typename U::NT = 0>
constexpr auto cast() const noexcept -> Int<typename U::NT> {
return Int<typename U::NT>{static_cast<typename U::NT>(v)};
}
};

对于类的大多数常见用例,有许多预定义的类型名称:

using Int8 = Int<int8_t>;
using Int16 = Int<int16_t>;
using Int32 = Int<int32_t>;
using Int64 = Int<int64_t>;

目标是自然地使用这个类的类型,但要使用一组方法。其中一种方法是.cast<>()方法,用于在以下整数类型之间进行转换:

int main(int argc, const char *argv[]) {
auto a = Int32{10};
auto b = a.cast<int64_t>();
auto c = a.cast<Int64>();
}

为了涵盖用户和模板中的广泛用途,强制转换模板参数应允许本机类型以及模板类作为参数。指定int64_tInt64或因此指定Int<int64_t>将导致完全相同的结果。

我想将第二个cast方法限制为Int模板类的值

示例中显示的方法将适用于任何在名称空间中具有名为NT的类型定义的类。在我的库中,NT通常用于模板类,它对cast方法的使用没有足够的限制。

下面的例子说明了我想避免的一种情况:

struct Unrelated {
using NT = int32_t;
};

int main(int argc, const char *argv[]) {
auto a = Int32{10};
auto b = a.cast<Unrelated>(); // NO! is confusing, shouldn't work.
}

是否有一种常用的方法来";启用";一个只包含自己类的模板实例的方法

  • 我知道C++2x中有一些简单的解决方案。然而,我需要一个使用C++17的解决方案
  • 接受所有积分类型的第一种铸造方法应保持完整

首先是Igor Tandetnik的一个类型特征(我自己的更丑(:

template<typename T> struct Int; // forward declaration
template <typename T> struct is_Int : std::false_type {};
template <typename T> struct is_Int<Int<T>> : std::true_type {};
template <typename T> inline constexpr bool is_Int_v = is_Int<T>::value;

然后您可以定义类及其cast,如下所示:

template<typename T>
struct Int {
static_assert(std::is_integral_v<T>); // no SFINAE needed so use static_assert
using NT = T;
T v;
explicit constexpr Int(T v) noexcept : v{v} {}

template<class U> // accept all, no SFINAE needed
constexpr auto cast() const noexcept {
// use static_assert instead
static_assert(std::is_integral_v<U> || is_Int_v<U>); // using the trait
// ...and constexpr-if:
if constexpr (std::is_integral_v<U>) return Int<U>{static_cast<U>(v)};
else return U{static_cast<typename U::NT>(v)};
}
};

最新更新