Ошибка в создании экземпляра шаблона в GCC 4.9, отлично работает в GCC 4.8
Приведенный ниже код теста отлично работает с GCC 4.8 (и 4.7):
#include <type_traits>
template<typename T, T &object, typename... Args>
struct Functor
{
template<float (T::*function)(Args...), Args... args>
struct Inner
{
float operator()() const
{
return (object.*function)(args...);
}
};
};
class Object
{
public:
float someFunction()
{
return {};
}
float someFunctionWithArgument(int)
{
return {};
}
};
Object object;
Functor<Object, object>::template Inner<&Object::someFunction> functor1;
Functor<Object, object, int>::template Inner<&Object::someFunctionWithArgument, 1> functor2;
int main()
{
}
Однако с GCC 4.9 он терпит неудачу с довольно бесполезным сообщением в момент создания functor1
:
$ g++ -std=c++11 test.cpp
test.cpp: In instantiation of ‘struct Functor<Object, (* & object)>’:
test.cpp:33:24: required from here
test.cpp:7:9: error: wrong number of template arguments (2, should be 1)
struct Inner
^
test.cpp:7:9: error: provided for ‘template<class T, T& object, class ... Args> template<float (T::* function)(Args ...), Args ...args> struct Functor<T, object, Args>::Inner’
test.cpp:7:9: error: wrong number of template arguments (2, should be 1)
test.cpp:7:9: error: provided for ‘template<class T, T& object, class ... Args> template<float (T::* function)(Args ...), Args ...args> struct Functor<T, object, Args>::Inner’
test.cpp:33:35: error: ‘Inner’ in ‘struct Functor<Object, (* & object)>’ does not name a template type
Functor<Object, object>::template Inner<&Object::someFunction> functor1;
Если я прокомментирую строку с помощью functor1
, все остальное (functor2
) отлично работает.
Любые идеи, как решить это?
EDIT:
Я сообщил об ошибке в GCC - https://gcc.gnu.org/bugzilla/show_bug.cgi?id=64514, который мы увидим...
Ответы
Ответ 1
Я не уверен, что GCC полностью ошибается. Однако проблему можно существенно свести к
template<typename... T>
struct Functor
{
template <T...>
struct Inner
{};
};
template struct Functor<>::Inner<>;
Что показывает то же поведение с GCC. Этот код, по-видимому, хорошо сформирован, хотя Inner
не имеет аргументов шаблона:
Когда N
равно нулю, инстанцирование расширения порождает пустую список. Такое создание не изменяет синтаксический интерпретация охватывающей конструкции, даже в тех случаях, когда в противном случае исключение списка в противном случае было бы плохо сформировано или приводит к двусмысленности в грамматике.
Но если теперь мы изменим код для использования шаблона псевдонимов, он внезапно начнет работать:
template <typename... T>
struct Functor
{
template <T...>
using Inner = void;
};
using type = Functor<>::Inner<>;
Демо. Пытаясь применить это решение к вашей проблеме, я не только столкнулся с исходной ошибкой, но и второй:
template <typename... Args>
struct Functor
{
template <Args... args>
struct A;
template <Args... args>
using B = A<args...>;
};
using type = Functor<>::B<>;
main.cpp: 8: 24: ошибка: шаблон расширения "args" не содержит аргументов пакеты
using B = A<args...>
^
Я думаю, что GCC имеет фундаментальную проблему с "пустыми" параметрами шаблона непигового типа.