2017-01-06 3 views
4

Просто интересно, почему это недействителен:Почему этот вариационный шаблон является ошибкой?

#include <iostream> 

template <std::size_t... Is> 
void foo(Is&&... args) { 
    std::cout << "foo called with " << sizeof...(Is) << "params\n"; 
} 

int main() { 
    foo(1, 2, 3, 4); 
} 

кажется вполне разумным пример, но он fails на любой компилятор я могу получить мои руки.

Если я использую size_t для class, то пример работает так, как ожидалось. Я также попытался использовать новый параметр шаблона auto, но ни один онлайн-компилятор не принял это, поэтому я не знаю, является ли это недопустимым вариантом использования или проблемой соответствия.

+4

'Is' не является типом. Это значение 'size_t'. – NathanOliver

+1

Вы никогда не напишете 'void foo (1 a, 2 b, 3 c, ...)', так зачем писать 'void foo (Is ...)'? ;) – Holt

+3

@BaummitAugen, что целевая доза не подходит правильно – NathanOliver

ответ

10

Это неправда C++, вот почему.

Если экземпляр этого шаблона функции с аргументами шаблона 1, 2, 3, 4 то после подстановки аргументов в шаблоне вы получите подпись:

void foo(1&&, 2&&, 3&&, 4&&); 

Это явно не действует функция.

Если вы хотите написать шаблон функции, которая принимает любое количество аргументов, но только если они имеют правильный тип, вы можете сделать это, как это в C++ 17:

template<typename T> 
    using is_size_t = std::is_same<T, std::size_t>; 

template<typename... T> 
    std::enable_if_t<std::conjunction<is_size_t<T>...>::value>> 
    foo(T&&... args); 

Или же (также с использованием C++ 17):

template<typename... T> 
    std::enable_if_t<(std::is_same_v<std::size_t, T> && ...)> 
    foo(T&&... args); 

для C++ 14 вы должны реализовать std::conjunction себя, например, используя шаблон and_ от p0032r1

+0

Я не думаю, что C++ 14 имеет складывающиеся выражения? – Barry

+1

@ Barry, oops, я забыл, как примитивен C++ 14;) –

+1

@JonathanWakely Это не примитивно, иначе оно завершено. – skypjack

2

В последнее время я работал с другим языком и полностью вытащил Монику. Просто, чтобы дополнить ответ Джонатана, (спасибо за пояснения и комментарии) это как обеспечить все параметры имеют size_t типа (то, что я на самом деле пытается сделать) using concepts:

template <class... Is> 
    requires (std::is_same<Is, int>::value && ...) 
void foo(Is&&... args) { /*...*/ } 

Или даже (ма FAV) путем определения выделенного понятия

template <class T> concept bool Integer = std::is_same<T, int>::value; 

template <Integer... Is> void foo(Is&&... args) { /*...*/ } 
//  ^^^^^^^awesome 

Live

+0

Понятия не являются частью языка C++. – Sjoerd

+1

@Sjoerd Я не говорю, что они есть, не так ли?Одной из причин задержки их добавления было то, что сообщество C++ экспериментирует, тестирует и разрабатывает на них –

Смежные вопросы