考虑以下代码:
struct A
{
template <typename T>
concept foo = true;
};
无法编译。我的Clang 10给出了错误:概念声明只能出现在全局或命名空间作用域中
,GCC也说了类似的话。
不允许这样做的原因是什么?即使封闭类是模板,我也看不出为什么它不能工作。
考虑以下代码:
struct A
{
template <typename T>
concept foo = true;
};
无法编译。我的Clang 10给出了错误:概念声明只能出现在全局或命名空间作用域中
,GCC也说了类似的话。
不允许这样做的原因是什么?即使封闭类是模板,我也看不出为什么它不能工作。
可能出现的根本困难在于概念可能会变得依赖:
template<class T>
struct A {
template<T::Q X>
void f();
};
X
是一个(依赖)类型为T::Q
的非类型模板参数(在C++20中不需要typename
),还是一个受概念T::Q
约束的类型模板参数?
规则是前者;我们需要新的语法(类似于typename
/template
)来表达其他可能性:也许像这样:
template<T::concept Q X> requires T::concept R<X*>
void A::g() {}
为什么需要这样做,在@DavisHerring的回答中有所讨论。在这个回答中,我想分享一个当我遇到这个问题时实际上正在寻找的模式。
根据您的用例,您可能不需要概念定义。如果您只是想避免SFINAE技巧,您可以直接调用requires语句,并摆脱类范围内的任何概念:
struct A
{
template<typename T>
auto operator()(T t) const
{
if constexpr(requires { t.foo(); })
{
std::cout<<"foo"<<std::endl;
}
else
{
std::cout<<"no foo"<<std::endl;
}
}
};
并将其用作
struct B { auto foo() {} };
struct C {};
int main()
{
A a;
a(B()); //prints "foo"
a(C()); //prints "no foo"
}
然而,如果你发现在类中多次使用相同的requires
语句,那么为什么不能在类范围内声明一次呢,这个问题是合理的。
因此,为了避免代码重复,你可以声明一个包含你要查找的概念的单个静态函数,例如:
struct A
{
template<typename T>
static constexpr auto concept_foo(T t)
{
return requires{ t.foo(); };
}
template<typename T>
auto operator()(T t) const
{
if constexpr(concept_foo(t))
{
std::cout<<"foo"<<std::endl;
}
else
{
std::cout<<"no foo"<<std::endl;
}
}
};
这种模式可以替代大多数类范围概念的使用情况。
if constexpr(requires { t.foo(); })
呢? - 303operator[]
,其他提供operator()
,当时我通过SFINAE分离了这两种情况)。更新后的版本也应该可以在没有模板技巧的情况下工作。 - davidhigh