例如,重载这两个:
// (a)
void doSomething(auto t) { /* */ }
// (b)
void doSomething(ConceptA auto t) { /* */ }
因此,当被调用时,编译器将在每个调用中匹配正确的函数:
doSomething(param_doesnt_adhere_to_ConceptA); // calls (a)
doSomething(param_adheres_to_ConceptA); // calls (b)
相关问题:概念会取代sfinae吗?
是的概念
就是为此目的而设计的。如果发送的参数不满足所需的概念参数,重载解析列表中将不考虑该函数,从而避免了歧义。
此外,如果一个发送的参数满足多个函数,则会选择更具体的一个。
简单的例子:
void print(auto t) {
std::cout << t << std::endl;
}
void print(std::integral auto i) {
std::cout << "integral: " << i << std::endl;
}
print("hello"); // calls print(auto)
print(7); // calls print(std::integral auto)
上面的示例演示了编译器如何更喜欢受约束类型(std::integral auto)而不是不受约束类型(仅为auto)。但这些规则也适用于两个相互竞争的概念。如果一个更具体,编译器应该选择更具体的一个。当然,如果这两个概念都满足,而且没有一个更具体,这将导致歧义。
那么,是什么让一个概念更具体呢?如果它基于另一个1。
泛型概念-GenericTwople:
template<class P>
concept GenericTwople = requires(P p) {
requires std::tuple_size<P>::value == 2;
std::get<0>(p);
std::get<1>(p);
};
class Any;
template<class Me, class TestAgainst>
concept type_matches =
std::same_as<TestAgainst, Any> ||
std::same_as<Me, TestAgainst> ||
std::derived_from<Me, TestAgainst>;
template<class P, class First, class Second>
concept Twople =
GenericTwople<P> && // <= note this line
type_matches<std::tuple_element_t<0, P>, First> &&
type_matches<std::tuple_element_t<1, P>, Second>;
GenericTwople<P> && // <= note this line
对于这一行带来的实际需求,Twople仍然具有相同的需求,但它将不再比GenericTwople更具体。这一点,当然还有代码重用,就是为什么我们更喜欢基于GenericTwople定义Twople。
现在我们可以玩各种过载:
void print(auto t) {
cout << t << endl;
}
void print(const GenericTwople auto& p) {
cout << "GenericTwople: " << std::get<0>(p) << ", " << std::get<1>(p) << endl;
}
void print(const Twople<int, int> auto& p) {
cout << "{int, int}: " << std::get<0>(p) << ", " << std::get<1>(p) << endl;
}
并用:
print(std::tuple{1, 2}); // goes to print(Twople<int, int>)
print(std::tuple{1, "two"}); // goes to print(GenericTwople)
print(std::pair{"three", 4}); // goes to print(GenericTwople)
print(std::array{5, 6}); // goes to print(Twople<int, int>)
print("hello"); // goes to print(auto)
struct A{
virtual ~A() = default;
virtual std::ostream& print(std::ostream& out = std::cout) const {
return out << "A";
}
friend std::ostream& operator<<(std::ostream& out, const A& a) {
return a.print(out);
}
};
struct B: A{
std::ostream& print(std::ostream& out = std::cout) const override {
return out << "B";
}
};
void print(const Twople<A, A> auto& p) {
cout << "{A, A}: " << std::get<0>(p) << ", " << std::get<1>(p) << endl;
}
print(std::pair{B{}, A{}}); // calls the specific print(Twople<A, A>)
不幸的是,C++20不允许概念专门化,否则我们会更进一步:
template<class P>
concept Twople<P, Any, Any> = GenericTwople<P>;
这可以为这个问题增加一个很好的可能的答案,但是概念专门化是不允许的。
1 约束偏序的实际规则更加复杂,请参见:cppreference/C++20规范。
请考虑以下代码示例: 我确信它不应该编译,因为编译器不应该能够选择两个构造函数中的一个。g-4.7.3显示了这个预期的行为:它说重载构造函数的调用是不明确的。但是,g-4.8.2成功编译了它。 此代码在 C 11 中是否正确,或者它是此版本 g 的错误/功能?
当我运行这段代码时,它会打印。我的问题是为什么没有编译时错误?对象和字符串的默认值为NULL。那么为什么不编译器说。
我希望有一个结构,它接受任意数量的lambdas,并作为所有调用操作符的中心调用点。 如果使用与构造时给出的任何 lambda 不匹配的参数列表调用调用运算符,则应调用默认调用运算符。 我以为下面的代码可以完全做到这一点。每个 lambda 的调用运算符都通过使用“提升”到 类。 当我在结构中没有默认的call操作符时,一切都像预期的那样工作(使用有效的参数列表)。如果我将它添加到结构中(如上面的
本文向大家介绍请解释Java中的概念,什么是构造函数?什么是构造函数重载?什么是复制构造函数?相关面试题,主要包含被问及请解释Java中的概念,什么是构造函数?什么是构造函数重载?什么是复制构造函数?时的应答技巧和注意事项,需要的朋友参考一下 考察点:JAVA构造函数 当新对象被创建的时候,构造函数会被调用。每一个类都有构造函数。在程序员没有给类提供构造函数的情况下,Java编译器会为这个类创建一
redux-saga 提供了一些辅助函数,用来在一些特定的 action 被发起到 Store 时派生任务。 这些辅助函数构建在低阶 API 之上。我们将会在高级概念一节看到这些函数是如何实现的。 第一个函数,takeEvery 是最常见的,它提供了类似 redux-thunk 的行为。 让我们演示一下常见的 AJAX 例子。每次点击 Fetch 按钮时,我们发起一个 FETCH_REQUESTE
本文向大家介绍PHP回调函数概念与用法实例分析,包括了PHP回调函数概念与用法实例分析的使用技巧和注意事项,需要的朋友参考一下 本文实例讲述了PHP回调函数概念与用法。分享给大家供大家参考,具体如下: 一、回调函数的概念 先看一下C语言里的回调函数:回调函数就是一个通过函数指针调用的函数。如果你把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用来调用其所指向的函数时,我们就说这是回调函数