使用非类型模板参数的 C++20 概念对类模板进行完全专业化

发布于 2025-01-11 00:47:40 字数 1509 浏览 0 评论 0原文

我对 C++20 概念相当陌生,我正在尝试创建一个模板类 Foo ,该类具有基于非类型(枚举器)模板参数的完全专门化的实现。我已经使用下面的代码测试了我的想法:

// Foo.h
#include <concepts>
#include <iostream>
#include <type_traits>

enum class Type { A, B, C };

template<std::is_enum T1, std::is_enum T2>
constexpr bool isEnumSame() { return T1 == T2; }

template<Type T> concept isTypeA = isEnumSame<T, Type::A>;
template<Type T> concept isTypeB = isEnumSame<T, Type::B>;

template<Type T>
struct Foo
{
   Foo() { std::cout << "Generic Foo\n"; }
};

template<Type T>
requires isTypeA<T>
struct Foo<T>
{
   Foo() { std::cout << "Type A Foo\n"; }
};

template<Type T>
requires isTypeB<T>
struct Foo<T>
{
   Foo() { std::cout << "Type B Foo\n"; }
};
// Foo.cpp
#include "Foo.h"

int main(void)
{
   Foo<Type::C> testC;
   Foo<Type::A> testA;
   Foo<Type::B> testB;

   return 0;
}

但是,我收到如下编译器错误(我使用 g++11 和 gcc11):

error: insufficient contextual information to determine type
   27 |       Foo<Type::C> testC;

对于 Foo也有类似的错误。 testAFoo测试B。有人可以告诉我我在这里可能做错了什么吗?另外,我理想情况下希望定义类似于以下内容的完整专业化:

template<isTypeA T>
struct Foo<T>
{
   Foo() { Print("Type A Foo"); }
};

但上面会产生编译器错误 error: 'isTypeA' does not constrain a type。任何帮助将不胜感激!

I am fairly new to C++20 Concepts and I am experimenting with creating a template class Foo with fully specialised implementations based on a non-type (enumerator) template parameter. I have tested my idea using the code below:

// Foo.h
#include <concepts>
#include <iostream>
#include <type_traits>

enum class Type { A, B, C };

template<std::is_enum T1, std::is_enum T2>
constexpr bool isEnumSame() { return T1 == T2; }

template<Type T> concept isTypeA = isEnumSame<T, Type::A>;
template<Type T> concept isTypeB = isEnumSame<T, Type::B>;

template<Type T>
struct Foo
{
   Foo() { std::cout << "Generic Foo\n"; }
};

template<Type T>
requires isTypeA<T>
struct Foo<T>
{
   Foo() { std::cout << "Type A Foo\n"; }
};

template<Type T>
requires isTypeB<T>
struct Foo<T>
{
   Foo() { std::cout << "Type B Foo\n"; }
};
// Foo.cpp
#include "Foo.h"

int main(void)
{
   Foo<Type::C> testC;
   Foo<Type::A> testA;
   Foo<Type::B> testB;

   return 0;
}

However, I get compiler errors like the following (I'm using g++11 and gcc11):

error: insufficient contextual information to determine type
   27 |       Foo<Type::C> testC;

and similarly for Foo<Type::A> testA and Foo<Type::B> testB. Can someone advise me on what I may be doing incorrectly here? Also, I would ideally like to define the full specialisations similar to:

template<isTypeA T>
struct Foo<T>
{
   Foo() { Print("Type A Foo"); }
};

but the above yields the compiler error error: ‘isTypeA’ does not constrain a type. Any help would be much appreciated!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

彩扇题诗 2025-01-18 00:47:40

std::is_enum 不是一个概念,因此这个谓词不会执行我认为您认为它会执行的操作:

template<std::is_enum T1, std::is_enum T2>
constexpr bool isEnumSame() { return T1 == T2; }

您可以直接获取 Type 值。另外,您的概念行需要像这样调用函数:

template<Type T1, Type T2>
constexpr bool isEnumSame() { return T1 == T2; }

template<Type T> concept isTypeA = isEnumSame<T, Type::A>();
template<Type T> concept isTypeB = isEnumSame<T, Type::B>();

如果您希望 isEnumSame 对任何枚举都是通用的:

template <class T>
concept Enumeration = std::is_enum_v<T>;

template<Enumeration auto T1, Enumeration auto T2>
constexpr bool isEnumSame() { return T1 == T2; }

std::is_enum is not a concept, so this predicate does not do what I assume you think it does:

template<std::is_enum T1, std::is_enum T2>
constexpr bool isEnumSame() { return T1 == T2; }

You can take Type values directly. Also, your concept lines need to call the functions like so:

template<Type T1, Type T2>
constexpr bool isEnumSame() { return T1 == T2; }

template<Type T> concept isTypeA = isEnumSame<T, Type::A>();
template<Type T> concept isTypeB = isEnumSame<T, Type::B>();

If you want your isEnumSame to be generic over any enumeration:

template <class T>
concept Enumeration = std::is_enum_v<T>;

template<Enumeration auto T1, Enumeration auto T2>
constexpr bool isEnumSame() { return T1 == T2; }
柠栀 2025-01-18 00:47:40

有几个问题:

  1. 模板
    

    is_enum 是一个特征,而不是一个概念。您可以使用诸如auto T1之类的东西,然后requires std::is_enum_v

  2. 模板<类型T>概念 isTypeA = isEnumSame;`
    

    您忘记调用该函数,请添加 ()


但你实际上并不需要任何这种概念魔法。您可以完全专门化 Foo 来获取枚举值:

template <>
struct Foo<Type::A> {...};

如果您出于某种原因不想完全专门化,您可以这样做:

template <Type T>
requires (T == Type::A)
struct Foo<T> {...};

There are several problems:

  1. template<std::is_enum T1, std::is_enum T2>
    

    is_enum is a trait, not a concept. You can use something like auto T1, and then requires std::is_enum_v<decltype(T1)>.

  2. template<Type T> concept isTypeA = isEnumSame<T, Type::A>;`
    

    You forgot to call the function, add ().


But you don't actually need any of this concept magic. You can fully specialize Foo for the enum values:

template <>
struct Foo<Type::A> {...};

If you for some reason don't want a full specialization, you can do this:

template <Type T>
requires (T == Type::A)
struct Foo<T> {...};
倾其所爱 2025-01-18 00:47:40

首先,std::is_enum不是一个概念,它只是一个普通的类,
因此像 template 这样的语法只是定义一个接受 std::is_enum,这不是您所期望的,并且不限制任何内容。

其次,bool isEnumSame()的模板参数不是类型,而是枚举值,因此应该定义为template

如果需要约束非类型模板参数的类型,可以使用 decltype 来获取其类型,然后使用 requires 表达式来约束它,如下所示:

enum class Type { A, B, C };

template<auto T1, auto T2>
  requires std::is_enum_v<decltype(T1)> && std::is_enum_v<decltype(T2)>
constexpr bool isEnumSame() { return T1 == T2; }

template<Type T> concept isTypeA = isEnumSame<T, Type::A>();
template<Type T> concept isTypeB = isEnumSame<T, Type::B>();

演示

First, std::is_enum is not a concept, it is just a normal class,
so a syntax like template<std::is_enum T1, std::is_enum T2> just defines a template function that accepts a non-type template parameter of type std::is_enum, which is not what you might expect and doesn't constrain anything.

Second, the template parameter of bool isEnumSame() is not a type but a enum value, so it should be defined as template<auto T1, auto T2>.

If you need to constrain the type of the non-type template parameter, you can just use decltype to get its type and use requires-expression to constrain it, like this:

enum class Type { A, B, C };

template<auto T1, auto T2>
  requires std::is_enum_v<decltype(T1)> && std::is_enum_v<decltype(T2)>
constexpr bool isEnumSame() { return T1 == T2; }

template<Type T> concept isTypeA = isEnumSame<T, Type::A>();
template<Type T> concept isTypeB = isEnumSame<T, Type::B>();

Demo

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文