CRTP: Как определить тип члена, который будет использоваться в качестве возвращаемого типа? - PullRequest
0 голосов
/ 05 мая 2018

Я бы хотел, чтобы тип возвращаемого значения базового метода CRTP зависел от типа члена в производном, как, например, в:

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; };

Что я должен поставить вместо ???

Я пробовал разные способы объявить тип возвращаемого значения:

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;
};

Единственные методы, которые компилируются, это int get_ok, для других я получаю либо (для 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; }
                                    ^

или (два других)

invalid use of incomplete type 'struct foo'
     typename T::value_type get_incomplete_type_foo() {  return static_cast<T*>(this)->value; }
                            ^

1 Ответ

0 голосов
/ 05 мая 2018

Я думаю, что единственный выход, доступный до c ++ 14, - это использовать черту типа:

#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;
}

онлайн-компилятор

Если Derived тип является шаблоном, специализация типа черты будет выглядеть следующим образом:

template<typename U>
struct Derived;

template<typename U> 
struct Value<Derived<U>>
{
    using type = float;
};
...