Функция рекурсивного шаблона Variadic - нет двусмысленности? - PullRequest
0 голосов
/ 23 ноября 2018

В настоящее время я изучаю шаблоны переменных, и в качестве небольшого упражнения, чтобы переварить некоторые вещи, о которых я читал, я написал небольшую функцию для вывода имен всех типов аргументов:

#include "stdafx.h"
#include <iostream>
#include <string>

template<typename Next, typename... Rest>
std::string get_arg_types(Next next, Rest... rest)
{
    return std::string(typeid(Next).name()) + "\n" + get_arg_types(rest...);
}

template<typename Last>
std::string get_arg_types(Last last)
{
    return std::string(typeid(Last).name());
}

int main()
{
    float f = 0;
    double d = 0;
    int i = 0;

    std::cout << get_arg_types(f, d, i);

    return 0;
}

К моему удивлению, это скомпилировано с использованием VC ++ 12.0 и (кажется) работает нормально.

Я ожидал ошибку из-за неоднозначности между перегрузками, когда остался только один аргумент, потому что я прочитал этот шаблонПакет параметров может быть пустым / содержать 0 аргументов.

Итак, мой вопрос: почему это работает?Как решается «потенциальная двусмысленность»?Разве подпись для обеих функций не идентична только с 1 аргументом?Мне кажется, что я где-то пропустил какую-то важную концепцию, потому что приведенный выше пример не должен компилироваться, но, очевидно, я ошибаюсь.

С уважением:)

1 Ответ

0 голосов
/ 23 ноября 2018

Ваш код проблематичен, но по другой причине.Как отмечалось в ответе на связанный вопрос Неоднозначный вызов при рекурсивном вызове перегрузки функции шаблона Variadic , вторая перегрузка в вашем коде считается более специализированной.Однако он должен отображаться перед подпрограммой с пакетом параметров.Компиляция вашего кода с помощью gcc 8.2.1 или clang 6.0.1 выдает ошибку, подобную

variadic.cpp: In instantiation of ‘std::__cxx11::string get_arg_types(Next, Rest ...) [with Next = int; Rest = {}; std::__cxx11::string = std::__cxx11::basic_string<char>]’:
variadic.cpp:7:67:   recursively required from ‘std::__cxx11::string get_arg_types(Next, Rest ...) [with Next = double; Rest = {int}; std::__cxx11::string = std::__cxx11::basic_string<char>]’
variadic.cpp:7:67:   required from ‘std::__cxx11::string get_arg_types(Next, Rest ...) [with Next = float; Rest = {double, int}; std::__cxx11::string = std::__cxx11::basic_string<char>]’
variadic.cpp:23:39:   required from here
variadic.cpp:7:67: error: no matching function for call to ‘get_arg_types()’
     return std::string(typeid(Next).name()) + "\n" + get_arg_types(rest...);
error: no matching function for call to ‘get_arg_types()

Как видно из ошибки, даже когда get_arg_types имеет единственный параметр, компиляторпринимает первую перегрузку, которая в свою очередь вызывает get_arg_types без аргументов.Простое решение состоит в том, чтобы переместить перегрузку get_arg_types с одним параметром перед процедурой с пакетом параметров шаблона или добавить объявление единственного параметра get_arg_types перед общей процедурой.

В качестве альтернативы,Вы можете исключить свой единственный параметр специализации get_arg_types и добавить специализацию с 0 параметрами:

std::string get_arg_types()
{
  return std::string();
}

Опять же, такая специализация должна быть помещена (или, по крайней мере, объявлена) перед процедурой шаблона.Обратите внимание, что с этим вторым решением выходные данные немного изменены.

...