Подтвердить что ты не робот

Ошибка в создании экземпляра шаблона в 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, который мы увидим...

4b9b3361

Ответ 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 имеет фундаментальную проблему с "пустыми" параметрами шаблона непигового типа.