如何对 T 中可能不存在的成员使用 decltype(T::member)

问题描述 投票:0回答:2

我正在寻找一种方法来定义一个变量,其类型取决于我的类模板化的类型的成员类型,但需要注意的是该成员变量可能不存在。由于我仅在成员确实存在的情况下访问

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;
}
c++ c++20 type-traits c++-concepts decltype
2个回答
2
投票

您可以创建一个老式类型特征来获取该类型:

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
投票

@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
用作后备。

© www.soinside.com 2019 - 2024. All rights reserved.