如何在未评估的上下文中获取应用于类成员的成员函数的结果类型

时间:2017-09-21 20:37:04

标签: c++

我甚至不确定这个问题的标题是否正确。我试图做的事情对我来说相当粗糙,所以我甚至不知道如何以简洁的方式描述它。对不起。

我有一个价值观的容器,包含在某种安全的#34;价值等级。我需要一个函数来获取指向该容器的指针,对其成员之一的引用以及以下情况发生:

如果传递的指针有效,则该函数返回包装值内的值。

如果传递的指针是nullptr,则该函数返回默认构造的值。

Anyhoo,这里有一些代码。

template<typename T>
class Wrapped {
    T t;
public:
    T& operator*() {
        return t;
    }
};

class Container {
public:
    Wrapped<int> i;
    Wrapped<string> s;
};

// Compiler error with R.
// I'd like R to be the return type of invoking operator* on the member that's represented by M.
// I've tried about 50 different versions of declarations to declare the type of R. This one feels like it most closely represents what I'm trying to achieve.
// R should be the T in Wrapped<T>.

template <typename T, typename M, typename R = decltype(declval<M>().operator*())>
R value_or_default(T* object, M member, R default_value = R{})
{
    object ? *((*object).*member) : default_value;
}

Container c;
auto actual_int = value_or_default(&c, &Container::i);    // Returns *(c.i).
auto default_string = value_or_default(nullptr, &Container::s);   // Returns string{}.

2 个答案:

答案 0 :(得分:2)

怎么样:

template<typename T>
class Wrapped {
    T t{};
public:
    T& operator*() {
        return t;
    }
};

class Container {
public:
    Wrapped<int> i;
    Wrapped<string> s;
};

template <typename T, typename R, typename C>
R value_or_default(T* object, Wrapped<R> C::* member)
{
    return *((*object).*member);
}

template <typename R, typename C>
R value_or_default(nullptr_t, Wrapped<R> C::*, R default_value = R{})
{
    return default_value;
}

int main() {
    Container c;
    auto actual_int = value_or_default(&c, &Container::i);    // Returns *(c.i).
    auto default_string = value_or_default(nullptr, &Container::s);   // Returns string{}.

    std::cout << actual_int << std::endl;
    std::cout << default_string << std::endl;
    return 0;
}

答案 1 :(得分:1)

我想你可以写

template <typename T, typename M,
   typename R = typename std::remove_reference<
                   decltype(*(std::declval<M>()))>::type>
R value_or_default (T * o, M T::*m)
 { return o ? *(o->*m) : R{}; }

但你必须调用nullptr案例来说明对象的类型(T),因为编译器无法从nullptr推断出它。

所以

Container c;

auto actual_int = value_or_default(&c, &Container::i);    // Returns *(c.i).
auto default_string = value_or_default<Container>(nullptr, &Container::s);
// ....................................^^^^^^^^^

static_assert(std::is_same<int, decltype(actual_int)>::value, "!");
static_assert(std::is_same<std::string, 
                           decltype(default_string)>::value, "!");