具有依赖参数类型的概念约束成员函数

Ale*_*oni 2 c++ c++-concepts c++20

我正在对概念进行一些实验,并且我试图限制成员函数,只有在满足概念时才必须实例化这些函数:

template <typename T>
concept Fooable = requires(T o)
{
    o.foo(uint());
};

template <typename T>
concept Barable = requires(T o)
{
    o.bar(uint());
};

class Foo
{
public:
    using FooType = int;
    void foo(uint) {}
};

class Bar
{
public:
    using BarType = double;
    void bar(uint) {}
};

template <typename T>
class C
{
public:
    void fun(typename T::FooType t) requires Fooable<T> {}
    void fun(typename T::BarType t) requires Barable<T> {}
};

int main()
{
    C<Foo> f;
}
Run Code Online (Sandbox Code Playgroud)

这段代码在 GCC 11.2 和 Clang 14 上都不能编译,说:

main.cpp: error: no type named 'BarType' in 'Foo'
main.cpp: error: no type named 'BarType' in 'Foo'
        void fun(typename T::BarType t) requires Barable<T> {}
                 ~~~~~~~~~~~~^~~~~~~
main.cpp: note: in instantiation of template class 'C<Foo>' requested here
        C<Foo> f;
               ^
Run Code Online (Sandbox Code Playgroud)

但是,由于我声明了一个C带有类型的对象Foo,所以我希望成员函数funwithBarType不会被实例化。

这可能是 GCC 和 Clang 的 bug 吗?或者我做错了什么?有什么方法可以使用概念来实现这一点吗?

康桓瑋*_*康桓瑋 5

由于fun不是模板函数,因此始终会被实例化,并且如果没有名为 的类型别名,typename T::BarType则会产生硬错误。你可能想做TBarType

template <typename T>
class C
{
public:
    template<Fooable U = T>
      requires requires { typename U::FooType; }
    void fun(typename U::FooType t);
    template<Barable U = T>
      requires requires { typename U::BarType; }
    void fun(typename U::BarType t);
};
Run Code Online (Sandbox Code Playgroud)

鉴于 与BarType概念 相关Barable,更合适的方法是将您的概念重新定义为(我替换uint()为因为标准中0U没有所谓的类型)uint

template<typename T>
concept Fooable = requires(T o) {
  o.foo(0U);
  typename T::FooType;
};

template<typename T>
concept Barable = requires(T o) {
  o.bar(0U);
  typename T::BarType;
};

template <typename T>
class C {
  public:
    template<Fooable F = T>
    void fun(typename F::FooType t);
    template<Barable B = T>
    void fun(typename B::BarType t);
};
Run Code Online (Sandbox Code Playgroud)

这要求满足的类型Barable必须有一个名为 的类型别名BarType