我如何专门化 std::common_type<A,B> 以使其自然可交换?
How can I specialize std::common_type<A,B> so that it's naturally commutative?
std::common_type<T1, ..., TN>
是 C++ 中的辅助模板,它可以找到所有 T1
... TN
都可以隐式转换为的通用类型。
根据 C++ 规范,如果某些条件适用,用户可以特化 std::common_type<T1,T2>
,并且:
std::common_type<T1, T2>::type
and std::common_type<T2, T1>::type
must denote the same type.
但是,common_type<T1, T2>
对于用户类型 T1
和 T2
:
可能是一个非常复杂的专业化
namespace std {
template <typename T1, complicated_constraint_of<T1> T2, ...>
struct common_type<complicated_expression_of<T1, ...>, complicated_expression_of<T2, ...>> {
using type = complicated_type_expression_of<T1,T2>;
};
}
一般来说,约束表达式不一定是对称的(例如,我们可以指定T2
是T1
的基)。这意味着为了保持对称性,我们需要用 T1
和 T2
颠倒来重写整个特化,但不犯任何错误地做到这一点是极其困难和脆弱的。
如何为我自己的类型稳健地定义 common_type<T1,T2>
的交换特化?
这是我想出的 C++20 解决方案:
// define concept of `common_type<A,B>` existing
template <typename A, typename B>
concept has_in_common_ordered = requires { common_type<A,B>::type; };
namespace std {
// define common_type<A,B> if common_type<B,A>::type exists:
template <typename A, has_in_common_ordered<A> B>
struct common_type<A,B> : public common_type<B,A> {};
}
现在,有了上面的内容,应该编译以下内容:
struct X {};
struct Y {};
namespace std {
template<>
struct common_type<X,Y> {
using type = X; // or whatever
};
}
int main() {
// even though we only specialized for one ordering,
// both orderings now exist:
std::common_type<X,Y>::type a;
std::common_type<Y,X>::type b;
}
我认为以下两种情况之一是可能的:
- 这是一种自然技术,应该真正成为
std::common_type
标准定义的一部分。
- 这是极其邪恶的,出于微妙的原因,你不应该这样做。
我在等待有人告诉我它在评论中是哪一个。 ;)
std::common_type<T1, ..., TN>
是 C++ 中的辅助模板,它可以找到所有 T1
... TN
都可以隐式转换为的通用类型。
根据 C++ 规范,如果某些条件适用,用户可以特化 std::common_type<T1,T2>
,并且:
std::common_type<T1, T2>::type
andstd::common_type<T2, T1>::type
must denote the same type.
但是,common_type<T1, T2>
对于用户类型 T1
和 T2
:
namespace std {
template <typename T1, complicated_constraint_of<T1> T2, ...>
struct common_type<complicated_expression_of<T1, ...>, complicated_expression_of<T2, ...>> {
using type = complicated_type_expression_of<T1,T2>;
};
}
一般来说,约束表达式不一定是对称的(例如,我们可以指定T2
是T1
的基)。这意味着为了保持对称性,我们需要用 T1
和 T2
颠倒来重写整个特化,但不犯任何错误地做到这一点是极其困难和脆弱的。
如何为我自己的类型稳健地定义 common_type<T1,T2>
的交换特化?
这是我想出的 C++20 解决方案:
// define concept of `common_type<A,B>` existing
template <typename A, typename B>
concept has_in_common_ordered = requires { common_type<A,B>::type; };
namespace std {
// define common_type<A,B> if common_type<B,A>::type exists:
template <typename A, has_in_common_ordered<A> B>
struct common_type<A,B> : public common_type<B,A> {};
}
现在,有了上面的内容,应该编译以下内容:
struct X {};
struct Y {};
namespace std {
template<>
struct common_type<X,Y> {
using type = X; // or whatever
};
}
int main() {
// even though we only specialized for one ordering,
// both orderings now exist:
std::common_type<X,Y>::type a;
std::common_type<Y,X>::type b;
}
我认为以下两种情况之一是可能的:
- 这是一种自然技术,应该真正成为
std::common_type
标准定义的一部分。 - 这是极其邪恶的,出于微妙的原因,你不应该这样做。
我在等待有人告诉我它在评论中是哪一个。 ;)