Как преодолеть ошибку MSVC из-за неудачного вывода аргумента шаблона указателя на метод-член? - PullRequest
3 голосов
/ 14 октября 2019

Ниже приведен минимальный код, который компилируется в g ++ , но дает ошибку в MSVC :

template<typename Type,
         typename Return,  // <--- error: this is not deduced
         typename Container,
         typename Parameter>
Container
StringTo (Type&& copy,
          const char tokens[],
          Return (Container::*Insert) (const Parameter&))
{
  static_assert(not std::is_lvalue_reference<Type>::value, "Must be rvalue.");
  Container container;
  return container;
}

template<typename Type>
auto
StringToVector (Type&& copy,
                const char tokens[])
{
  static_assert(not std::is_lvalue_reference<Type>::value, "Must be rvalue.");
  return StringTo(std::move(copy), tokens, &std::vector<Type>::push_back); // <--- here
}

int main()
{
  auto v = StringToVector(std::string("hello world"), " ");
}

Согласно этому сообщению, это ошибка в MSVCкоторый еще не исправлен: Visual Studio 2017 - не удалось вывести аргумент шаблона (с переменными шаблонами)

Вопрос : Как обойти эту проблему для этого конкретногоcase?


Обновление : эта ошибка не устраняется, и я открыт для изменения дизайна / интерфейса. Вы можете опубликовать это как ответ. Приму лучший.

Ответы [ 3 ]

4 голосов
/ 14 октября 2019

Добавив тип контейнера, который вы хотите, к списку параметров шаблона StringTo, а затем взяв функцию за универсальный тип, вы можете использовать лямбду в StringToVector для пересылки к правильной функции-члену. Это выглядело бы как

template<typename Container,
         typename Type,
         typename Func>
Container
StringTo (Type&& copy,
          const char tokens[],
          Func func)
{
  static_assert(not std::is_lvalue_reference<Type>::value, "Must be rvalue.");
  Container container;
  func(container, std::move(copy));
  return container;
}

template<typename Type>
auto
StringToVector (Type&& copy,
                const char tokens[])
{
  static_assert(not std::is_lvalue_reference<Type>::value, "Must be rvalue.");
  return StringTo<std::vector<Type>>(std::move(copy), tokens, [](auto& cont, auto&& val){ cont.push_back(std::move(val)); } ); // <--- here
}

int main()
{
  auto v = StringToVector(std::string("hello world"), " ");
}

И вы можете увидеть, как это работает на Rextester здесь: https://rextester.com/BLSS95194

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

Более худой дизайн мог бы просто сделать:

template<typename Type>
auto
StringToVector (Type&& copy,
                const char tokens[])//what are we going to use this for ?
{
  return std::vector{ copy };
}

Попробуйте сами на Godbolt

Это будет полезная работа-где-то?


Другой подход может заключаться в том, чтобы вместо этого использовать дизайн настройки, основанный на типах, с самого начала (пример использования std::back_insert_iterator)

#include <utility>
#include <string>
#include <vector>

template<typename Container,
         typename Inserter,
         typename Type
         >
Container
StringTo (Type&& copy,
          const char tokens[])
{
  static_assert(!std::is_lvalue_reference<Type>::value, "Must be rvalue.");
  Container container;
  *Inserter(container) = copy;
  return container;
}

template<typename Type>
auto
StringToVector (Type&& copy,
                const char tokens[])
{
  static_assert(!std::is_lvalue_reference<Type>::value, "Must be rvalue.");
  return StringTo<std::vector<Type>, std::back_insert_iterator<std::vector<Type> > >(std::move(copy), tokens); 
}

int main()
{
  auto v = StringToVector(std::string("hello world"), " ");
}

Попробуйте сами

0 голосов
/ 15 октября 2019

Обходной путь 1

Задайте проблемный параметр в качестве первого типа шаблона и передайте его явно.

template<typename Parameter,
         typename Return,
         typename Container>
Container
StringTo (Parameter&& copy,
          const char tokens[],
          Return (Container::*Insert) (const Parameter&))
{
  Container container;
  // do something ...
  return container;
}

template<typename Type>
auto
StringToVector (Type&& copy,
                const char tokens[])
{
  return StringTo<Type>(std::move(copy), tokens, &std::vector<Type>::push_back);
} //             ^^^^^^ here (explicit)                       ^^^^ passed anyways

Демо


Обходной путь 2

Если мы скомпрометируем часть Type и будем напрямую использовать std::string, то эта ошибка также исчезнет в MSVC.

template<typename Return,
         typename Container>
Container
StringTo (std::string&& copy, // Type --> std::string
          const char tokens[],
          Return (Container::*Insert) (const std::string&))
{
  Container container;
  // do something ...
  return container;
}

inline
auto
StringToVector (std::string&& copy,
                const char tokens[])
{
  return StringTo(std::move(copy), tokens, &std::vector<std::string>::push_back);
}

Demo .

...