使用概念选择类模板特化 [英] Using concepts to select class template specialization
问题描述
这个问题 演示了如何使用 C++20 概念为 函数 模板选择重载.我正在尝试做一些类似的事情:为 class 模板选择 specializations.
This question demonstrates how to use C++20 concepts to choose overloads for a function template. I'm trying to do something analogous: choose specializations for a class template.
我从 Angle
的类模板开始,它包装了一个包含以弧度表示的角度的浮点值.使用概念,我可以确保用户不会使用浮点类型以外的任何东西实例化 Angle
:
I'm starting with a class template for Angle<T>
which wraps a floating point value containing an angle in radians. Using concepts, I can ensure that users don't instantiate Angle
with anything other than a floating point type:
template <std::floating_point T> struct Angle { T m_radians; };
后来,我决定让客户使用可以处理整数类型的 Angle
的独特实现.换句话说,我想允许这样的代码:
Later, I decided I'd like to let clients use a distinct implementation of Angle<T>
that can handle integral types. In other words, I'd like to allow code like:
const auto theta = Angle<float>(3.14f);
const auto phi = Angle<int>(180);
所以我尝试添加一个类似的模板.
So I tried adding a comparable template.
template <std::integral T> struct Angle { T m_degrees; };
编译器将此附加实现视为具有不同约束的模板的重新声明.我尝试了几种不同的方式来表达我的意图,但没有一种方法能满足我尝试过的任何编译器.事实上,我什至找不到用 std::enable_if
和传统 SFINAE 来做到这一点的方法——不可否认,我完全有可能不太了解 SFINAE.
The compilers view this additional implementation as a redeclaration of the template with a different constraint. I've tried several different ways of expressing my intent, but none satisfy any of the compilers I've tried. In fact, I cannot even find a way to do this with std::enable_if
and traditional SFINAE--admittedly, it's entirely possible I don't understand SFINAE very well.
我发现的唯一方法是对每个整数和浮点类型进行不同的专门化.
The only approach I've found requires making distinct specializations for each of the integral and floating point types.
template <std::floating_point T> struct AngleRad { T m_radians; };
template <std::integral T> struct AngleDeg { T m_degrees; };
template <typename T> struct Angle2 {};
template <> struct Angle2<float> : public AngleRad<float> {};
template <> struct Angle2<double> : public AngleRad<double> {};
template <> struct Angle2<long double> : public AngleRad<long double> {};
template <> struct Angle2<short> : public AngleDeg<short> {};
template <> struct Angle2<int> : public AngleDeg<int> {};
template <> struct Angle2<long> : public AngleDeg<long> {};
template <> struct Angle2<long long> : public AngleDeg<long long> {};
template <> struct Angle2<unsigned short> : public AngleDeg<unsigned short> {};
template <> struct Angle2<unsigned int> : public AngleDeg<unsigned int> {};
template <> struct Angle2<unsigned long> : public AngleDeg<unsigned long> {};
template <> struct Angle2<unsigned long long> : public AngleDeg<unsigned long long> {};
[是的,我知道还有一些整数类型.我只是想说明这一点.这个例子是为了简单而设计的,尽管它的灵感来自于实际代码.]
[Yes, I know there are a few more integral types. I'm just trying to illustrate the point. This example is contrived for simplicity, though it's inspired by actual code.]
有没有办法用概念来更简单地表达这一点?
Is there a way to use concepts to express this more simply?
推荐答案
你说
template<typename T> // requires (std::integral<T> || std::floating_point<T>) // optional
struct Angle;
template<std::integral T> struct Angle<T> { T m_degrees; };
template<std::floating_point T> struct Angle<T> { T m_radians; };
需要使用足够大的域来声明模板以包含其所有特化.
The template needs to be declared with a big enough domain to contain all of its specializations.
这篇关于使用概念选择类模板特化的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!