如何在使用C++20概念时手动消除部分专门化的歧义?

ej83mcc0  于 11个月前  发布在  其他
关注(0)|答案(2)|浏览(95)

如果我定义了两个概念,并对每个概念都有一个类的部分特化,那么很明显,如果我有一个类型满足这两个概念,我就有一个二义性:

#include <cstdio>

template <typename T>
concept HasBar = requires {
   typename T::Bar;
};

template <typename T>
concept HasBaz = requires {
   typename T::Baz;
};

template <typename T>
struct Foo;

template <typename T> requires(HasBar<T>)
struct Foo<T> {
    static void frobnicate() {
        fprintf(stderr, "HasBar!\n");
    }
};

template <typename T> requires(HasBaz<T>)
struct Foo<T> {
    static void frobnicate() {
        fprintf(stderr, "HasBaz!\n");
    }
};

int main() {
   struct MyFoo {
      using Bar = int;
      using Baz = float;
   };
   
   Foo<MyFoo>::frobnicate();
}

字符串
产量:

<source>:42:15: error: ambiguous partial specializations of 'Foo<MyFoo>'
   42 |    Foo<MyFoo> foo;
      |               ^
<source>:23:8: note: partial specialization matches [with T = MyFoo]
   23 | struct Foo<T> {
      |        ^
<source>:30:8: note: partial specialization matches [with T = MyFoo]
   30 | struct Foo<T> {
      |        ^


如果我从Foo中删除Baz类型,那么一切都会按照计划进行,它会打印HasBar!
当专门化像这样模糊不清时,我想手动指定一个优先级。我想我可以用一堆标签类型来做,较低的值代表较高的优先级:

#include <cstdio>

template <int N>
struct Priority : Priority<N-1> {};

template <>
struct Priority<0> {};

template <typename T>
concept HasBar = requires {
   typename T::Bar;
};

template <typename T>
concept HasBaz = requires {
   typename T::Baz;
};

template <typename T, typename Enabled = void>
struct Foo;

template <typename T> requires(HasBar<T>)
struct Foo<T, Priority<1>> {
    static void frobnicate() {
        fprintf(stderr, "HasBar!\n");
    }
};

template <typename T> requires(HasBaz<T>)
struct Foo<T, Priority<0>> {
    static void frobnicate() {
        fprintf(stderr, "HasBaz!\n");
    }
};

int main() {
   struct MyFoo {
      using Bar = int;
      using Baz = float;
   };
   
   Foo<MyFoo>::frobnicate();
}


但这似乎只是完全排除了两个部分专业化:

<source>:42:4: error: implicit instantiation of undefined template 'Foo<MyFoo>'
   42 |    Foo<MyFoo>::frobnicate();


在新的C++20概念世界中应该如何做到这一点?

mrfwxfqh

mrfwxfqh1#

如果在这种情况下Bar应该具有优先级,则可以要求HasBaz<T>的专门化也不具有Bar

template <typename T> requires(HasBaz<T> && !HasBar<T>)
//                                          ^^^^^^^^^^
struct Foo<T> {
    static void frobnicate() {
        fprintf(stderr, "HasBaz!\n");
    }
};

字符串
输出量:

HasBar!


如果从MyFoo中删除Bar

int main() {
   struct MyFoo {
      //using Bar = int;
      using Baz = float;
   };
   
   Foo<MyFoo>::frobnicate();
}


输出量:

HasBaz!

py49o6xq

py49o6xq2#

你可以在函数重载中使用优先级:

template <typename T>
requires(HasBar<T>)
void frobnicate(Priority<1>) { fprintf(stderr, "HasBar!\n"); }

template <typename T>
requires(HasBaz<T>)
void frobnicate(Priority<0>) { fprintf(stderr, "HasBaz!\n"); }

template <typename T>
void frobnicate() { frobnicate<T>(Priority<1>{}); }

字符串
Demo

相关问题