тип, определенный с использованием, не может использоваться в качестве параметра функции - PullRequest
0 голосов
/ 17 октября 2019

В моем приложении из реального мира я использую CRTP для создания более-менее большого «стека» классов. Мне нужно знать, какова "общая база" этих классов, поэтому я определяю внутри одного из классов "стека" a type с using. Позже я не хочу использовать этот определенный тип как шаблонный параметр функции, но это не будет работать, я всегда сталкиваюсь с «не могу определить параметр шаблона« VAR_TYPE »» с g ++.

Есть лишанс исправить эту проблему, потому что не рекомендуется определять тип вручную, потому что он должен изменяться автоматически, если изменится структура моего «стека классов».

template < typename T> struct B { using HERE = B<T>; };
template < typename T> struct C: public B<T> { };

template <typename T>
using COMMON_BASE = typename C<T>::HERE;

template < typename T>
void Print2(  )
{
    std::cout << __PRETTY_FUNCTION__ << std::endl;
}

// g++ reports:
// error: no matching function for call to 'CheckMe(COMMON_BASE<int>*&)'
// note: candidate: 'template<class VAR_TYPE> void CheckMe(COMMON_BASE<VAR_TYPE>*)'
// note:   template argument deduction/substitution failed:
// note:   couldn't deduce template parameter 'VAR_TYPE'

template < typename VAR_TYPE >
void CheckMe( COMMON_BASE<VAR_TYPE>* ) { std::cout << "COMMON_BASE<>" << std::endl; }

// "hardcoded" works fine but should be avoided
//template < typename VAR_TYPE >
//void CheckMe( B<VAR_TYPE>* ) { std::cout << "B<>" << std::endl; }

void CheckMe( int* ) { std::cout << "int" << std::endl; }
//void CheckMe( ... ){ std::cout << "default" << std::endl; }

int main()
{
    COMMON_BASE< int >* cb;
    B<int>* bi;
    CheckMe( cb );
    CheckMe( bi );
    Print2< COMMON_BASE<int>* >(); // gives: void Print2() [with T = B<int>*]
}

1 Ответ

1 голос
/ 17 октября 2019

К сожалению, вывод аргументов шаблона работает только в непосредственном контексте, и иначе было бы нелогично поступать иначе. Подумайте об этом примере:

template<typename T>
using common_base = std::conditional<(sizeof(T) > 8), int, float>

template<typename T>
void call_me(common_base<T>) {
    // ...
}

int main() {
    call_me(1.4f); // What is T?
}

Это может показаться очевидным, но это также и то, что происходит с вашим примером. Вы можете себе представить это:

// Ah! Fooled you compiler!
template<> struct B<int> { using HERE = B<std::string>; };

Затем, после чего, что эти вызовы должны выводить?

CheckMe(bi); // should deduce B<int> or B<std::string>?

Как вы можете видеть, компилятор не может вывести через не непосредственный контекст, так какможет не быть отношения 1: 1, а иногда оно просто не может быть вычтено.


Что делать тогда?

Упрощение функции шаблона - это обычный способ сделатьэто работает:

template<typename T>
struct B {
    using HERE = B<T>;
    using type = T;
};

template<typename BaseType>
void CheckMe(BaseType* bt) {
    using VAR_TYPE = BaseType::type; // yay, can use member type
}
...