Следующий код представляет собой пример учебной реверсивной перегруженной функции. В обоих лязгом и GCC, он компилируется и main
возвращает 36 (как и ожидалось):Является ли переменная шаблона переменной C++ 11 переменной переменной неоднозначной?
template <typename T>
int add(T val)
{
return val;
}
template <typename FirstTypeT, typename... RestT>
int add(FirstTypeT first_value, RestT... rest)
{
return first_value + add<RestT...>(rest...);
}
int main(void)
{
return add(12, 12, 12);
}
Однако, здесь есть небольшая модификация. Он использует зависимый тип в определении шаблона вместо параметра шаблона непосредственно:
struct Foo
{
using SomeType = int;
};
template <typename T>
int add(typename T::SomeType val)
{
return val;
}
template <typename FirstT, typename... RestT>
int add(typename FirstT::SomeType first_value, typename RestT::SomeType... rest)
{
return first_value + add<RestT...>(rest...);
}
int main(void)
{
return add<Foo, Foo, Foo>(12, 12, 12);
}
Это компилирует и работает как задумано с использованием GCC 5.2, но fails с помощью лязг 3.8:
clang++ variadic.cpp -o var -std=c++11 -Wall
variadic.cpp:15:26: error: call to 'add' is ambiguous
return first_value + add<RestT...>(rest...);
^~~~~~~~~~~~~
variadic.cpp:15:26: note: in instantiation of function template specialization 'add<Foo, Foo>' requested here
return first_value + add<RestT...>(rest...);
^
variadic.cpp:20:12: note: in instantiation of function template specialization 'add<Foo, Foo, Foo>' requested here
return add<Foo, Foo, Foo>(12, 12, 12);
^
variadic.cpp:7:5: note: candidate function [with T = Foo]
int add(typename T::SomeType val)
^
variadic.cpp:13:5: note: candidate function [with FirstT = Foo, RestT = <>]
int add(typename FirstT::SomeType first_value, typename RestT::SomeType... rest)
^
1 error generated.
Мой вопрос двоякий ,
- Является ли это на самом деле является допустимым использование параметра шаблона пакета TYPENAME применить оператор разрешения области видимости для каждого члена стаи, как в
typename RestT::SomeType...
? - Является ли clang правильным по отношению к стандарту, или это ошибка? Является ли второй пример действительно более неоднозначным, чем первый? (Для первого примера, кажется, что вы могли бы сказать, что единственная перегрузка аргумента неоднозначная с вторым экземпляром с
RestT = <>
)
MSVC15 компилирует оба образца. Кланг здесь странный, но у меня нет стандартной ссылки, чтобы сказать, кто прав, а кто не прав. – Niall
Исходя из этого дефекта ([CWG1395] (http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1395)), я думаю, что это ошибка clang. Я не могу найти ничего о том, почему встроенный тип изменит ситуацию. – Niall
Частичное упорядочение здесь сложно, так как все находится в невыводимом контексте. –