问题
I would like to make the return type of a CRTP base method depend on the type of a member in the derived, as for example in:
template <typename C>
struct sum_a_b {
??? sum() { return static_cast<C*>(this)->a + static_cast<C*>(this)->b; }
}
template <typename T> struct a_b : sum_a_b<a_b<T>> { T a,b; };
What should I put in place of ???
I tried different ways to declare the return type :
template <typename T>
struct base {
int get_ok() {
return static_cast<T*>(this)->value;
}
auto get_invalid() -> decltype(static_cast<T*>(this)->value) {
return static_cast<T*>(this)->value;
}
typename T::value_type get_incomplete_type_foo() {
return static_cast<T*>(this)->value;
}
auto get_incomplete_type_again() -> decltype(T().value) {
return static_cast<T*>(this)->value;
}
};
struct foo : base<foo> {
typedef int value_type;
value_type value;
};
The only methods that compiles is int get_ok
, for the others I get either (for get_invalid_cast
):
invalid static_cast from type 'base<foo>*' to type 'foo*'
auto get_invalid() -> decltype(static_cast<T*>(this)->value) { return static_cast<T*>(this)->value; }
^
or (the other two)
invalid use of incomplete type 'struct foo'
typename T::value_type get_incomplete_type_foo() { return static_cast<T*>(this)->value; }
^
回答1:
I think the only workaround available prior to c++14 is to use a type trait:
#include <iostream>
template<typename T>
struct Value;
template <typename T>
struct Base
{
typename Value<T>::type get_value(void)
{
return static_cast<T*>(this)->m_value;
}
};
struct Derived;
template<>
struct Value<Derived>
{
using type = float;
};
struct Derived: public Base<Derived>
{
Value<Derived>::type m_value{};
};
int main()
{
Derived derived{};
std::cout << derived.get_value() << std::endl;
}
online compiler
If Derived
type is a template then type trait specialization would look like this:
template<typename U>
struct Derived;
template<typename U>
struct Value<Derived<U>>
{
using type = float;
};
来源:https://stackoverflow.com/questions/50188172/crtp-how-to-infer-type-of-member-to-be-used-as-return-type