提问人:DottyPhone 提问时间:9/23/2023 最后编辑:Jan SchultkeDottyPhone 更新时间:9/23/2023 访问量:118
如何将 decltype(T::member) 用于 T 中可能不存在的成员
How to use decltype(T::member) for a member that might not exist in T
问:
我正在寻找一种方法来定义一个具有类型的变量,具体取决于我的类模板化所针对的类型的成员的类型,但需要注意的是,成员变量可能不存在。由于我只在成员确实存在的情况下访问块中的变量,因此我不关心声明它或它是什么类型。但是,我了解到这是行不通的,因为未使用的分支仍然需要编译。constexpr
typename conditional<hasMember<T>, decltype(T::member), int>
以下是我希望开始工作的一个例子:
#include <iostream>
using namespace std;
struct X{};
struct Y{string member;};
template<class T>
concept hasMember = requires (T t) {t.member;};
template<class T>
struct A{
void hi(T a) {
// stuff
typename conditional<hasMember<T>, decltype(T::member), int /*member is unused if hasMember<T> is false, so I don't care what type it is or if it exists*/>::type member;
if constexpr (hasMember<T>){
member = a.member;
}
// stuff
if constexpr (hasMember<T>){
std::cout << member<< std::endl;
}
};
};
int main() {
X x;
Y y{"hi"};
// Does not compile
// A<X> ax;
// ax.hi(x);
// Compiles and runs fine
A<Y> ay;
ay.hi(y);
return 0;
}
答:
3赞
Ted Lyngmo
9/23/2023
#1
您可以创建一个老式类型特征来获取该类型:
template<class T, class O>
struct member_or {
static O test(...);
template<class U = T>
static auto test(int) -> decltype(U::member);
using type = decltype(test(0));
};
template<class T, class O>
using member_or_t = member_or<T, O>::type;
然后,您的实现可以是:A
template <class T>
struct A {
void hi(T a) {
// stuff
member_or_t<T, int> member; // <- now no problem
if constexpr (hasMember<T>) {
member = a.member;
}
// stuff
if constexpr (hasMember<T>) {
std::cout << member << std::endl;
}
};
};
评论
0赞
DottyPhone
9/23/2023
谢谢,我已经去了,这很好用。最后一个问题,是否可以创建一个以使其更通用,或者它必须是一个语句?member_or_t<T, std::monostate> member;
variable_or_t<T, member, std::monostate>
#define
1赞
Ted Lyngmo
9/23/2023
@DottyPhone 不客气。我认为你需要涉及宏才能做出这样的东西。
5赞
Jan Schultke
9/23/2023
#2
@TedLyngmo的解决方案是可靠的,还有更多选择。 您可以简单地依靠编译器已经延迟实例化所有模板的事实,并定义一个类模板:
template <typename T>
struct member_type {
using type = decltype(T::member);
};
只要您不访问 ,就不会发生实例化。
这可以在以下方面被利用:::type
member_type
std::conditional_t
using M = std::conditional_t<hasMember<T>, member_type<T>, std::type_identity<int>>::type;
M member;
选择包含这些类型的类模板,而不是有条件地选择 和 。然后,仅访问所选类模板,其中用作回退。decltype(T::member)
int
::type
::type
std::type_identity
1赞
康桓瑋
9/23/2023
#3
您可以只使用 lambda 初始化局部变量,例如memebr
void hi(T a) {
auto member = [&] {
if constexpr (hasMember<T>)
return a.member;
else
return 0;
}();
// stuff
if constexpr (hasMember<T>){
std::cout << member<< std::endl;
}
};
0赞
Jarod42
9/23/2023
#4
由于我只在成员确实存在的情况下访问块中的变量,因此我不关心声明它或它是什么类型。
constexpr
那么为什么要在非 constexpr 块中使用它呢?
你可以简单地重写你的函数,这样:
template<class T>
struct A{
void hi(T a) {
// ...
auto do_stuff = [](){ /*stuff*/ };
if constexpr (hasMember<T>){
using MemberType = decltype(T::member);
const MemberType member = a.member;
do_stuff();
std::cout << member << std::endl;
} else {
do_stuff();
}
// ...
};
};
评论
//stuff
if constexpr