【问题标题】:Get member from last possible class of a parameter pack获取来自最后一类参数包的成员
【发布时间】:2021-04-22 20:22:57
【问题描述】:

我想获取参数包中最后一个可能的类的成员变量的值。

例如。我希望getLastB(a_, b_, c_, d_) 在下面的代码中返回 100(c_.b 的值),而不是 40(b_.b 的值)

#include <type_traits>
#include <iostream>

#define ADD_HAS_MEM_VAR_CHECKER(var, name)                              \
    template<typename T>                                                \
    struct name {                                                       \
        typedef char yes[1];                                            \
        typedef char no [2];                                            \
        template <typename _1> static yes &chk(decltype(_1::b));        \
        template <typename   > static no  &chk(...);                    \
        static bool const value = sizeof(chk<T>(0)) == sizeof(yes);     \
    }


ADD_HAS_MEM_VAR_CHECKER(b, has_b);

template<typename Arg, typename... Args>
struct has_b_parampack {
    static bool const value = has_b<Arg>::value or has_b_parampack<Args...>::value;
};

template<typename Arg>
struct has_b_parampack<Arg> {
    static bool const value = has_b<Arg>::value;
};


template <typename Arg, typename... Args>
typename std::enable_if<has_b_parampack<Args...>::value, int>::type
getLastB(Arg first, Args&&... args) {
    return getLastB(args...);
}

template <typename Arg, typename... Args>
typename std::enable_if<!has_b_parampack<Args...>::value, int>::type
getLastB(Arg first, Args&&... args) {
    return first.b;
}


struct A {int a = 10;};
struct B {int b = 40;};
struct C {int c = 30;int b = 100;};
struct D {int d = 30;};


int main() {
    A a_;
    B b_;
    C c_;
    D d_;

    std::cout << "has B parampack A, B, C, D= " << has_b_parampack<A, B, C, D>::value << std::endl;
    std::cout << "has B parampack B, C, D= " << has_b_parampack<B, C, D>::value << std::endl;
    std::cout << "has B parampack C, D= " << has_b_parampack<C, D>::value << std::endl;
    std::cout << "has B parampack D= " << has_b_parampack<D>::value << std::endl;

    std::cout << "Last B = " << getLastB(a_, b_, c_, d_) << "\n";
    return 0;
}

但是当我尝试编译这段代码时,我得到一个错误

lastMemberOfParamPack.cpp: In instantiation of ‘typename std::enable_if<(! has_b_parampack<Args ...>::value), int>::type getLastB(Arg, Args&& ...) [with Arg = A; Args = {B&, C&, D&}; typename std::enable_if<(! has_b_parampack<Args ...>::value), int>::type = int]’:
lastMemberOfParamPack.cpp:58:56:   required from here
lastMemberOfParamPack.cpp:37:18: error: ‘struct A’ has no member named ‘b’
     return first.b;

如果我注释我从 main 调用 getLastB 的行,代码会编译并且它会给出 4 个打印语句的预期值。

has B parampack A, B, C, D= 1
has B parampack B, C, D= 1
has B parampack C, D= 1
has B parampack D= 0

有什么想法我在这里可能做错了吗?

【问题讨论】:

    标签: c++ variadic-templates template-meta-programming sfinae parameter-pack


    【解决方案1】:

    您需要从T 中删除引用

    static bool const value = sizeof(chk<typename std::remove_reference<T>::type>(0)) == sizeof(yes);
    

    如果最后一个包含b,或者b 不是int 类型,您的代码也会失败。


    如果你可以使用 C++17,你可以这样写:

    template<typename T>                                               
    struct has_b {                                                     
        typedef char yes[1];
        typedef char no [2];
        template <typename S> static yes& chk(decltype(S::b));
        template <typename  > static no & chk(...);
        static bool const value = sizeof(chk<typename std::remove_reference<T>::type>(0)) == sizeof(yes);
    };
    
    template <typename Arg, typename... Args>
    auto getLastB(Arg& first, Args&... args) {
        if constexpr((has_b<Args>::value or...))
            return getLastB(args...);
        else
            return first.b;
    }
    

    【讨论】:

      【解决方案2】:

      因为我不太确定c++2a,所以我将把它作为单独的答案。


      借助Concept 支持,您可以更轻松地编写它(主要是HasB 部分)

      template <typename T>
      concept HasB = requires(T t){t.b;};
      
      template <typename T, typename... Ts> 
      requires (HasB<T> or ... or HasB<Ts>) // optional SFINAE
      auto getLastB(T& first, Ts&... rest){
          if constexpr((HasB<Ts> or...))
              return getLastB(rest...);
          else if constexpr(HasB<T>) // optional check
              return first.b; 
          else{ // optional else
              static_assert(HasB<T>,"no");
              return 1;
          }
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-05-19
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多