Ошибка вывода аргумента шаблона шаблона с GCC (работает с MSVC) - PullRequest
0 голосов
/ 24 июня 2018

У меня есть следующий достаточно простой шаблон функции:

template <class OrderedSetType, template<class> class SupersetType>
OrderedSetType f(const SupersetType<OrderedSetType>& superset)
{
    return OrderedSetType();
}

Он называется так:

f(std::vector<std::string>());

И компилятору не удается определить параметр шаблона.Диагностическое сообщение не особенно полезно:

<source>: In function 'int main()':

<source>:12:33: error: no matching function for call to 'f(std::vector<std::__cxx11::basic_string<char> >)'

     f(std::vector<std::string>());

                                 ^

<source>:5:16: note: candidate: template<class OrderedSetType, template<class> class SupersetType> OrderedSetType f(const SupersetType<OrderedSetType>&)

 OrderedSetType f(const SupersetType<OrderedSetType>& superset)

                ^

<source>:5:16: note:   template argument deduction/substitution failed:

<source>:12:33: note:   template parameters of a template template argument are inconsistent with other deduced template arguments

     f(std::vector<std::string>());

                                 ^

Почему возникает ошибка?Бывает с GCC 7.3 с -std=c++14, не бывает с -std=c++17.Какие изменения в стандарте C ++ 17 позволили скомпилировать этот код?И можно ли сделать так, чтобы он компилировался для C ++ 14?

Вот демонстрационная версия: https://godbolt.org/g/89BTzz

Кстати, задание аргументов шаблона явно не помогает.

PS. Между тем MSVC не имеет проблем с этим фрагментом кода, но clang 5 и 6 не могут скомпилировать его даже в режиме C ++ 17.Поэтому либо clang имеет ошибку и не может скомпилировать код, соответствующий стандарту, либо GCC имеет ошибку и успешно компилирует код, которого не должно (с -std=c++17).

Ответы [ 3 ]

0 голосов
/ 24 июня 2018

Хотя это не дает ответа на вашу проблему, оно предоставляет альтернативу.

Помните, что все стандартные контейнеры имеют открытый тип с именем value_type. Это означает, что вы можете легко пропустить шаблон шаблона и получить только что-то вроде

template<typename ContainerT>
typename ContainerT::value_type f(ContainerT const& superset)
{
    return typename ContainerT::value_type();
}

Пока ваш SupersetType следует стандартным контейнерам с элементом value_type, он должен работать.

0 голосов
/ 24 июня 2018

Какие изменения в стандарте C ++ 17 позволили скомпилировать этот код?

Вы объявляете параметр шаблона шаблона SupersetType, содержащий только один параметр шаблона, но у аргумента шаблона шаблона std::vector<std::string> есть два параметра, т. Е. std::string и аргумент шаблона по умолчанию std::allocator<string>. До C ++ 17 они не совпадают и приводят к ошибке (тогда вы должны сделать так, чтобы они совпадали, чтобы решить проблему), так как C ++ 17 ( CWG 150 ) разрешено; то есть аргументы шаблона по умолчанию разрешены для аргумента шаблона шаблона, чтобы соответствовать параметру шаблона шаблона с меньшим количеством параметров шаблона.

template<class T> class A { /* ... */ };
template<class T, class U = T> class B { /* ... */ };
template <class ...Types> class C { /* ... */ };

template<template<class> class P> class X { /* ... */ };
X<A> xa; // OK
X<B> xb; // OK in C++17 after CWG 150
         // Error earlier: not an exact match
X<C> xc; // OK in C++17 after CWG 150
         // Error earlier: not an exact match
0 голосов
/ 24 июня 2018

Попробуйте с

template <template <typename...> class SupersetType,
          typename FirstT, typename ... OthersTs>
FirstT f (SupersetType<FirstT, OthersTs...> const & superset)
 { return FirstT{}; }

или также

template <template <typename...> class SupersetType, typename FirstT>
FirstT f (SupersetType<FirstT> const & superset)
 { return FirstT{}; }

Проблема в том, что std::vector не принимает только тип, но два;второй - это распределитель со значением по умолчанию.

Таким образом, вы должны принять во внимание эту проблему.

Очевидно, что вы можете написать f() с параметром шаблона-шаблона, который принимает только два типа

template <template <typename, typename> class SupersetType,
          typename FirstT, typename SecondT>
FirstT f (SupersetType<FirstT, SecondT> const & superset)
 { return FirstT{}; }

, но если вы используете параметр шаблона, который принимает переменный список типов, у вас есть более гибкий f() (который соответствует большему количеству контейнеров)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...