static class 特征上的条件执行路径
conditional execution path on static class trait
我在尝试实现现有 API 的新 API 替代方案时遇到了问题,我仍然想支持它以实现向后兼容性;
让这成为我的老API:
typedef int[3] Node;
template <class T>
struct convert{
static std::pair<bool, T> decode(Node node);
}
//and a call to this construct here
template<typename T>
T decode_for_me(Node node) {
return convert<T>::decode(node).second;
}
//with a specialization, for example a custom type
struct custom_type {int a; int b;};
template<>
struct convert<custom_type>{
static std::pair<bool, custom_type> decode(Node node) {
custom_type c; c.a=node[0]; c.b=node[1]; return std::make_pair(true, c); };
};
int main() {
Node node = {1,2};
decode_for_me<custom_type>(node);
return 0;
}
现在想将 convert::decode 更改为更苗条的签名并刷新 API 以实现更多类型:
class alt_type {
int x; int y; int z;
alt_type(int x, int y, int z) : x(x), y(y), z(z) {};
}
template<>
struct convert<alt_type>{
static alt_type decode_new_api(Node node) {return {node[0], node[1], node[2]};};
}
我现在如何在 convert<T>
的 class-layout/trait 上实施条件切换到 select 正确的调用路径,将 decode_for_me<T>()
替换为:
template<typename T>
T decode_for_me(Node node) {
if constexpr ( "has_trait<convert<T>, "decode">" ) //<<<<
return convert<T>::decode(node).second;
if constexpr ( "has_trait<convert<T>, "decode_new_api">" ) // <<<<
return convert<T>::decode_new_api(node);
throw std::runtime_error();
}
我在 SFINAE 中研究了一些类似的问题和答案,这些问题和答案从模板构造到使用 decltype
和 declval
有所不同。然而,所有这些都涉及成员函数,而在这里我对静态评估感兴趣。我也可以让 none 为我工作。
感谢您的帮助!
我不知道如何使用接收方法名称(解码或 decode_new_api)作为参数的单个 type-traits 来解决此问题。
但是,如果您接受针对不同方法的不同测试,一个可能的解决方案是声明几个(无需定义)函数来测试“declare”
template <typename>
std::false_type has_decode (long);
template <typename T>
auto has_decode (int)
-> decltype( T::decode(std::declval<Node>()), std::true_type{});
还有一对“declare_new_api”
template <typename>
std::false_type has_decode_new_api (long);
template <typename T>
auto has_decode_new_api (int)
-> decltype( T::decode_new_api(std::declval<Node>()), std::true_type{});
现在你的decode_for_me()
变成了
template <typename T>
T decode_for_me(Node node) {
if constexpr ( decltype(has_decode<convert<T>>(0))::value )
return convert<T>::decode(node).second;
if constexpr ( decltype(has_decode_new_api<convert<T>>(0))::value )
return convert<T>::decode_new_api(node);
throw std::runtime_error("no decode");
}
我在尝试实现现有 API 的新 API 替代方案时遇到了问题,我仍然想支持它以实现向后兼容性;
让这成为我的老API:
typedef int[3] Node;
template <class T>
struct convert{
static std::pair<bool, T> decode(Node node);
}
//and a call to this construct here
template<typename T>
T decode_for_me(Node node) {
return convert<T>::decode(node).second;
}
//with a specialization, for example a custom type
struct custom_type {int a; int b;};
template<>
struct convert<custom_type>{
static std::pair<bool, custom_type> decode(Node node) {
custom_type c; c.a=node[0]; c.b=node[1]; return std::make_pair(true, c); };
};
int main() {
Node node = {1,2};
decode_for_me<custom_type>(node);
return 0;
}
现在想将 convert::decode 更改为更苗条的签名并刷新 API 以实现更多类型:
class alt_type {
int x; int y; int z;
alt_type(int x, int y, int z) : x(x), y(y), z(z) {};
}
template<>
struct convert<alt_type>{
static alt_type decode_new_api(Node node) {return {node[0], node[1], node[2]};};
}
我现在如何在 convert<T>
的 class-layout/trait 上实施条件切换到 select 正确的调用路径,将 decode_for_me<T>()
替换为:
template<typename T>
T decode_for_me(Node node) {
if constexpr ( "has_trait<convert<T>, "decode">" ) //<<<<
return convert<T>::decode(node).second;
if constexpr ( "has_trait<convert<T>, "decode_new_api">" ) // <<<<
return convert<T>::decode_new_api(node);
throw std::runtime_error();
}
我在 SFINAE 中研究了一些类似的问题和答案,这些问题和答案从模板构造到使用 decltype
和 declval
有所不同。然而,所有这些都涉及成员函数,而在这里我对静态评估感兴趣。我也可以让 none 为我工作。
感谢您的帮助!
我不知道如何使用接收方法名称(解码或 decode_new_api)作为参数的单个 type-traits 来解决此问题。
但是,如果您接受针对不同方法的不同测试,一个可能的解决方案是声明几个(无需定义)函数来测试“declare”
template <typename>
std::false_type has_decode (long);
template <typename T>
auto has_decode (int)
-> decltype( T::decode(std::declval<Node>()), std::true_type{});
还有一对“declare_new_api”
template <typename>
std::false_type has_decode_new_api (long);
template <typename T>
auto has_decode_new_api (int)
-> decltype( T::decode_new_api(std::declval<Node>()), std::true_type{});
现在你的decode_for_me()
变成了
template <typename T>
T decode_for_me(Node node) {
if constexpr ( decltype(has_decode<convert<T>>(0))::value )
return convert<T>::decode(node).second;
if constexpr ( decltype(has_decode_new_api<convert<T>>(0))::value )
return convert<T>::decode_new_api(node);
throw std::runtime_error("no decode");
}