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 中研究了一些类似的问题和答案,这些问题和答案从模板构造到使用 decltypedeclval 有所不同。然而,所有这些都涉及成员函数,而在这里我对静态评估感兴趣。我也可以让 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");
}