从参数包的最后一个可能 class 获取成员
Get member from last possible class of a parameter pack
我想获取参数包中最后一个可能class的成员变量的值。
例如。我希望下面代码中的 getLastB(a_, b_, c_, d_)
到 return 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
知道我这里可能做错了什么吗?
您需要从 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;
}
因为我不太确定 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;
}
}
我想获取参数包中最后一个可能class的成员变量的值。
例如。我希望下面代码中的 getLastB(a_, b_, c_, d_)
到 return 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
知道我这里可能做错了什么吗?
您需要从 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;
}
因为我不太确定 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;
}
}