除了 Nicol Bolas 的精彩回答:
概念有点特殊,因为它们的行为不像其他模板化的东西:
13.7.9 Concept definitions
(5) 未实例化概念 ([temp.spec])。
[注意1:concept-id ([temp.names]) 被评估为表达式。概念不能显式实例化 ([temp.explicit])、显式特化 ([temp.expl.spec]) 或部分特化 ([temp.spec.partial])。 — 尾注]
由于概念不能被实例化,它们也不能被特化。
我不确定为什么标准决定不让它们专业化,因为它很容易模仿专业化。
虽然您不能直接对概念进行专门化,但有很多方法可以解决这个问题。
您可以在概念中使用任何类型的常量表达式 - 因此您可以使用模板化变量(可以专门化)并将其包装成一个概念 - 该标准针对其自身的许多概念执行此操作好吧,例如std::is_intergral:
template<class T> struct is_integral;
// is_integral is specialized for integral types to have value == true
// and all others are value == false
template<class T>
inline constexpr bool is_integral_v = is_integral<T>::value;
template<class T>
concept integral = is_integral_v<T>;
因此,您可以轻松编写具有以下特化的概念:godbolt example
struct Foo{};
struct Bar{};
template<class T>
constexpr inline bool is_addable_v = requires(T t) {
{ t + t } -> std::same_as<T>;
};
// Specializations (could also use other requires clauses here)
template<>
constexpr inline bool is_addable_v<Foo> = true;
template<class T>
constexpr inline bool is_addable_v<T&&> = true;
template<class T>
concept is_addable = is_addable_v<T>;
int main() {
static_assert(is_addable<int>);
static_assert(is_addable<Foo>);
static_assert(!is_addable<Bar>);
static_assert(is_addable<Bar&&>);
}
或者通过使用一个类:
template<class T>
struct is_addable_v : std::true_type {};
template<>
struct is_addable_v<struct FooBar> : std::false_type {};
template<class T>
concept is_addable = is_addable_v<T>::value;
甚至是 constexpr lambda:godbolt example
// pointers must add to int
// everything else must add to double
template<class T>
concept is_special_addable = ([](){
if constexpr(std::is_pointer_v<T>)
return requires(std::remove_pointer_t<T> t) {
{ t + t } -> std::same_as<int>;
};
else
return requires(T t) {
{ t + t } -> std::same_as<double>;
};
})();
int main() {
static_assert(is_special_addable<double>);
static_assert(is_special_addable<int*>);
static_assert(!is_special_addable<double*>);
static_assert(!is_special_addable<int>);
}
因此,虽然概念不能单独专门化,但使用现有语言功能很容易达到相同的效果。