2016-08-19 2 views
3

У меня есть следующий сценарий:C++ шаблон вычет не может вывести аргумент шаблона

struct AP; 
struct B 
{ 
    B() : m(2) {} 
    int m; 
}; 

struct A : private B 
{ 
    A() : B(), n(1) {} 
private: 
    int n; 
    friend AP; 
}; 

struct AP 
{ 
    AP(A& a) : a_(a) {} 

    template<typename T> 
    struct A_B { 
     using type = typename std::enable_if< std::is_base_of< typename std::remove_reference<T>::type, 
                   A >::value, 
                    T >::type; 
    }; 

    template<typename T> 
    operator typename A_B<T>::type() 
    { 
     return static_cast<T>(a_); 
    } 

    template<typename T> 
    typename A_B<T>::type get() 
    { 
     return static_cast<T>(a_); 
    } 

    int& n() { return a_.n; } 
private: 
    A& a_; 
}; 

int main() 
{ 
    A a; 
    AP ap(a); 
    ap.n() = 7; 
    const B& b = ap.get<const B&>(); 
    //const B& b = ap; candidate template ignored: couldn't infer template argument 'T' 
    //auto b = static_cast<const B&>(ap); candidate template ignored: couldn't infer template argument 'T' 
    std::cout<<b.m; 
} 

комментируемого линии не будет компилировать. Clang ++ отмечает, что «шаблон-кандидат игнорируется: не удалось вывести шаблонный аргумент« T »«

Почему я не могу получить ссылку на базу А с оператором литья? Я думаю, что код будет выглядеть намного приятнее.

+1

Вашей комментировали линию попытаться преобразовать 'ap' в ссылку типа' b' а ' ap 'имеет тип' AP', который не имеет отношения к 'B' или' A'. Как вы ожидаете, что это сработает? – wasthishelpful

+0

@wasthishelpful: Я думаю, что OP пытается сделать, это преобразовать элемент 'a_' экземпляра' AP' в 'B', который должен быть действительным, потому что' A' происходит от 'B'. – AndyG

ответ

0

Я нашел ответ здесь: http://www.mersenneforum.org/showthread.php?t=18076

Это ключ: «если вы хотите, чтобы компилятор выводить типы аргументов, эти типы не должны быть зависимыми типами»

При этом он компилирует:

template<typename T> 
operator T() 
{ 
    static_assert(std::is_base_of< typename std::remove_reference<T>::type,A >::value, 
         "You may cast AP only to A's base classes."); 
    return static_cast<T>(a_); 
} 
1

ответ, который вы писали работы, но является излишеством, если вы действительно не хотите static_assert сообщение.

Классических шаблонные прекрасно работает в данном случае, потому что A уже конвертирована в B:

struct AP 
{ 
    AP(A& a) : a_(a) {} 

    template<typename T> 
    operator T() 
    { 
     return a_; 
    } 

    template<typename T> 
    T get() 
    { 
     return a_; 
    } 

    int& n() { return a_.n; } 
private: 
    A& a_; 
}; 

Demo

Смежные вопросы