Не удается вывести параметр шаблона при использовании вспомогательной структуры шаблона

Я хотел бы, чтобы некоторые функции шаблона работали с существующими помощниками шаблонной структуры. Однако вывод аргумента шаблона не удается. Есть ли обходной путь?

Пример

Этот перегруженный operator << компилируется и работает:

template <typename T>
inline typename std::vector<T>&
operator<<(
    typename std::vector<T>& vec,
    const typename std::vector<T>::value_type& val)
{
    vec.push_back(val);
    return vec;
}

Но когда я пытаюсь использовать помощник struct, это не компилируется:

template<typename T>
struct Vector
{
    typedef std::vector<T> Type;
};

template <typename T>
inline typename Vector<T>::Type&
operator<<(
    typename Vector<T>::Type& vec,
    const typename Vector<T>::Type::value_type& val)
{
    vec.push_back(val);
    return vec;
}

ошибка gcc:

error: no match for 'operator<<' (operand types are 'std::vector<int>' and 'int')
    ...
note: candidate: 
'template<class T> typename Vector<T>::Type& operator<<
(typename Vector<T>::Type&, const typename Vector<T>::Type::value_type&)'
 operator<<(
 ^~~~~~~~
note:   template argument deduction/substitution failed:
note:   couldn't deduce template parameter 'T'

клан ошибка:

error: invalid operands to binary expression ('std::vector<int>' and 'int')
   vec << int(2);
   ~~~ ^  ~~~~~~
note: candidate template ignored: couldn't infer template argument 'T'
operator<<(
^

Живой пример

Вопрос

  • Что мешает успешному выводу параметров шаблона в этом случае?
  • Есть ли обходной путь c++03 для этого случая? Шаблоны псевдонимов решат проблему в c++11.

Примечание. В моей реальной задаче вторым параметром не обязательно является T, и я не могу использовать его для определения типа вектора.

Примечание 2: реальная вспомогательная структура содержит предварительную обработку для конкретной платформы и выглядит примерно так:

template <class T>
struct Helper
{
#if defined(_WIN32_WCE)
    typedef std::vector<T, WMHeapAllocator<T> > Vector;  
#else
    typedef std::vector<T> Vector;      
#endif
};

person AMA    schedule 02.02.2018    source источник
comment
в C<T>::Type, T невозможно вывести (у нас может быть (в общем случае) несколько T, которые совпадают). (что также имеет место в первом фрагменте с ::value_type, поэтому T выводится только из первого параметра).   -  person Jarod42    schedule 02.02.2018


Ответы (1)


Это невыводимые контексты, которые не ограничиваются C++03. См. мой предыдущий ответ параметр шаблона не может быть выведен.

Что касается обходного пути, вам нужно сделать один из аргументов в функции, где можно вывести T. Как только он будет выведен из одного места, компилятор будет использовать его в других местах.

В вашем случае, если вы можете быть уверены, что value_type будет T, тогда используйте это:

template <typename T>
inline typename Vector<T>::Type&
operator<<(
    typename Vector<T>::Type& vec,
    const T& val)
{
    vec.push_back(val);
    return vec;
}

Здесь T выводится из второго аргумента и используется в первом.

ИЗМЕНИТЬ (чтобы отразить редактирование вопроса)

Вам не нужен вспомогательный класс, решение шаблона шаблона может быть лучше:

template<template<typename, typename> class Container, class T, class U>
inline Container<T, U>&
operator<<(
        Container<T, U>& vec,
        const typename Container<T, U>::value_type& val)
{
    vec.push_back(val);
    return vec;
}
person llllllllll    schedule 02.02.2018
comment
К сожалению, в моей реальной проблеме второй параметр не обязательно связан с T. Я обновил ответ. - person AMA; 02.02.2018
comment
Возможно, вы можете попробовать параметр шаблона шаблона вместо вспомогательного класса. - person llllllllll; 02.02.2018
comment
Ага, умно. Итак, вы предлагаете сделать что-то вроде это? - person AMA; 02.02.2018
comment
Смотрите мой обновленный ответ. На самом деле вам не нужен этот вспомогательный класс, если его единственной целью является хранение информации о времени компиляции внутреннего типа. Ваш код не будет компилироваться, потому что это все еще невыведенный контекст. - person llllllllll; 02.02.2018
comment
Но это компилируется. Согласитесь, что в этом случае мне не нужен помощник в функции шаблона. - person AMA; 02.02.2018
comment
Это явная вызываемая версия std::vector, а не версия параметра шаблона шаблона. Если вы удалите std::vector версию <<, произойдет сбой. - person llllllllll; 02.02.2018
comment
Да, мы говорим о немного разных вещах :) В моем случае полная специализация на std::vector решает проблему и будет работать с существующими хелперами (см. Примечание 2 в вопросе). Я также думаю, что это легче читать. - person AMA; 02.02.2018