Почему использование пакета параметров целочисленного значения запрещено после пакета параметров типа в С++ 11?

Вопрос почти не имеет смысла без примера. Итак, вот что я пытаюсь сделать.

В целом С++ позволяет следующее:

template<class T, class U, T t, U u>
void func() {}

func<char, int, 'A', 10>();

Но похоже, что его естественное вариативное расширение не работает.

template<class...T, T... t>
void func() {}

func<char, int, 'A', 10>(); 

И clang, и g++4.7 отвергают приведенный выше код. Ошибка отображается там, где выполняется создание экземпляра. Мне кажется, что два вариативных списка должны анализироваться однозначно, потому что первый имеет типы, а другой имеет только целые значения.

Если вышеизложенное не предназначено для работы, я думаю, что следующее тоже не сработает.

template <class Ret, class... Args, Ret (*func)(Args...)>
class Foo {};

Я думаю, что шаблон Foo — довольно полезная штука.


person Sumant    schedule 12.01.2012    source источник
comment
Шаблон Foo был бы похож на template<typename T, T>, последний параметр шаблона на самом деле вообще ничего не добавляет и, следовательно, совершенно не нужен, в конце концов, тип может быть прекрасно выражен с использованием параметров шаблона (например, typedef Ret(*func)(Args...) внутри Foo)   -  person Grizzly    schedule 12.01.2012
comment
@Grizzly: последний параметр не предоставляет type (который можно заменить на typedef), он предоставляет указатель на функцию. Указатель функции, который заменяется во время компиляции, что позволяет выполнять кросс-процедурную оптимизацию, например встраивание.   -  person Ben Voigt    schedule 12.01.2012
comment
@Sumant: Вы правы в том, что это кажется недвусмысленным, однако я думаю, что Стандарт просто стремился к простоте, указав, что пакет параметров был последним возможным параметром, и после этого ничего не могло произойти. Это упрощает согласование.   -  person Matthieu M.    schedule 12.01.2012
comment
@Ben Voigt: Ах, ты прав, конечно. Примечание для себя: не следует делать такие комментарии посреди ночи.   -  person Grizzly    schedule 12.01.2012


Ответы (2)


(Дополнительно: Непосредственно отвечая на свой первый вопрос, вы также можете превратить template<class...T, T... t> void func() {} в шаблон внутри шаблона. Это не работает в g++ 4.6, но работает в clang 3.0, поэтому мне потребовалось время, чтобы найти его.)

Поместите шаблон внутри шаблона:

template<class ... T>
struct func_types {
   template <T ... t>
   static void func_values() {
       // This next line is just a demonstration, and 
       // would need to be changed for other types:
       printf("%c %d\n", t...);
   }
};

int main() {
    func_types<char, int> :: func_values<'A', 10>();
}

Приемлем ли шаблон внутри шаблона? Альтернативой является использование кортежей с func< tuple<char,int> , make_tuple('A',10) >. Я думаю, что это выполнимо, но вам, возможно, придется свернуть свой собственный класс кортежа (похоже, что make_tuple не является constexpr.

Наконец, вы можете реализовать свой шаблон Foo следующим образом:

template<typename Ret, typename ...Args>
struct Foo {
        template< Ret (*func)(Args...)>
        struct Bar {
                template<typename T...>
                Bar(T&&... args) {
                        cout << "executing the function gives: "
                           << func(std::forward(args)...) << endl;
                }
        };
};

int main () {
    Foo<size_t, const char*> ::  Bar<strlen> test1("hi");
    Foo<int, const char*, const char*> ::  Bar<strcmp> test2("compare","these");
}

Последний код находится на ideone. Чтобы продемонстрировать, я реализовал конструктор для пересылки аргументов функции, код которой находится в шаблоне.

person Aaron McDaid    schedule 12.01.2012
comment
Обратите внимание, что использовать Args&&... плохо, так как идеальная переадресация основана на выводе аргументов шаблона. Однако вы указываете типы аргументов явно, поэтому это избыточно. - person Xeo; 12.01.2012
comment
Ах да, @Xeo. Я должен заменить func(args...) на func(std::forward(args...), так как в противном случае rvalues ​​потеряют свою rvalue-ness (при условии, что наш func действительно принял rvalue)? Это имеет смысл для меня. Есть ли какая-то другая тонкость, которую я упускаю? - person Aaron McDaid; 12.01.2012
comment
.. о, на самом деле, я думаю, что мне также нужно сделать сам конструктор шаблоном, чтобы он получал эти дедукции. - person Aaron McDaid; 12.01.2012
comment
Я пробовал это решение раньше. Проблема в том, что типы в сигнатуре функции должны вручную передаваться в шаблон внешнего класса. Невозможно вывести типы из указателя на функцию и в то же время передать его как параметр значения шаблона. Дедукция работает только тогда, когда указатель на функцию передается как обычный параметр функции. Оттуда он не может стать частью списка параметров шаблона. Я буду счастлив оказаться неправым. - person Sumant; 12.01.2012
comment
@Sumant, я не уверен, какова твоя цель. Можете ли вы привести пример того, как вы хотели бы иметь возможность использовать Foo? Вы хотите иметь возможность выполнить typedef Foo<strcmp> f;, а затем использовать f для доступа к полученной информации о функции strcmp, возможно, f :: num_args будет числом аргументов для strlen. Это то, что вы хотели? (Я не уверен, что это возможно, но мне любопытна ваша конечная цель) - person Aaron McDaid; 13.01.2012
comment
@Sumant, я думаю, что можно вывести типы из указателя функции и в то же время передать его как параметр значения шаблона, если вы готовы заключить его в макрос. Я думаю, мы можем заставить работать typedef MAGICAL_MACRO(strlen) t; (где t будет иметь тот тип, который, я думаю, вам нужен), даже если мы не сможем заставить работать typedef GreatTemplate<strlen> t;. Это то, что вы ищите? Я добился прогресса в последние часы по связанным вопросам, мне нравится думать об этом! - person Aaron McDaid; 13.01.2012
comment
@Sumant, вот урезанная версия с обещанным макросом. Он автоматически выводит все типы и так далее. Вы также можете найти этот вопрос и ответ полезным; Я задал свой вопрос о дедукции. - person Aaron McDaid; 13.01.2012
comment
@ Аарон, спасибо за ответ. Вот как я его использовал: /2012/01/ Сразу переходите к части static_memoizer. - person Sumant; 21.01.2012
comment
Это интересно, @Sumant. Недавно я сам немного запомнился — пока писал код на C++, чтобы позволить себе больше использовать стиль Haskell для манипулирования списками. В любом случае, хороший пост. Рад, что был полезен. - person Aaron McDaid; 22.01.2012

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

person Johannes Schaub - litb    schedule 12.01.2012