Странная ошибка C2275 ... незаконное использование этого типа в качестве выражения с шаблоном-функцией-членом и лямбдами - PullRequest
3 голосов
/ 22 июня 2011

Сводка

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

Подробности

Сначала у меня есть базовый класс, в котором хранятся function экземпляры.в vector.Только производные классы могут добавлять function экземпляры к этому vector, вызывая add_external.Все function экземпляры могут быть публично вызваны путем вызова invoke_externals.Производный класс будет добавлять лямбда-выражения как function экземпляров.Эти лямбды, в свою очередь, будут вызывать шаблон функции базового класса invoke_internal с другой «внутренней» лямбдой.Параметр шаблона для invoke_internal является типом исключения, который будет явно перехвачен при выполнении «внутренней» лямбды в invoke_internal:

using namespace std;

class base
{
public:
    void invoke_externals()
    {
        for (auto it = funcs_.begin(); it != funcs_.end(); ++it)
        {
            (*it)();
        }
    }

protected:
    void add_external(function<void(void)> func)
    {
        funcs_.push_back(func);
    }

    template <typename T>
    void invoke_internal(function<void(void)> func)
    {
        try
        {
            func();
        }
        catch (const T&){}
        catch (...){}
    }

    vector<function<void(void)>> funcs_;
};

Тогда у меня есть две тривиальные свободные функции, которые выдают logic_error иruntime_error исключений.Эти функции должны использоваться во «внутренней» лямбде, которая вызывается в invoke_internal:

void throws_logic_error()
{
    throw logic_error("");
}

void throws_runtime_error()
{
    throw runtime_error("");
}

В конструкторе класса derived две лямбды добавляются с помощью add_external.Каждую из этих лямбд называют invoke_internal «внутренними» лямбдами.Первый вызов invoke_internal явно поймает logic_error, который throws_logic_error сгенерирует.Второй вызов invoke_internal явно поймает runtime_error, который выбросит throws_runtime_error.

class derived : public base
{
public:
    derived()
    {
        add_external([this]()
        {
            invoke_internal<logic_error>([]()
            {
                throws_logic_error();
            });
        });

        add_external([this]()
        {
            invoke_internal<runtime_error>([]()
            {
                throws_runtime_error();
            }); 
        });
    }
};

И чтобы связать все это вместе, создается экземпляр derived и вызывается invoke_externals для вызова«внешние» лямбды добавлены в конструктор derived.Эти «внешние» лямбды, в свою очередь, будут вызывать «внутренние» лямбды, и сгенерированные исключения будут явно перехвачены:

int wmain(int, wchar_t*[])
{
    derived().invoke_externals();

    return 0;
}

Проблема

Однако вышеприведенныйне компилируется:

error C2275: 'std::logic_error' : illegal use of this type as an expression
error C2275: 'std::runtime_error' : illegal use of this type as an expression

... выдается для вызовов invoke_internal в конструкторе derived.

Если я перемещаю invoke_internal из base исделать его свободной функцией, затем скомпилировать.

Вопрос

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

Примечание: Перемещение функции-нарушителя из base не является оптимальным, поскольку в моем сценарии реальной жизни функция фактически выполняетиспользовать состояние своего класса по-разному.

Ответы [ 2 ]

5 голосов
/ 22 июня 2011

Благодаря ответу @ sehe я сам смог проверить это на VS2010.Работает следующий код:

derived()
{   //                       vvvvvvvvvvvvvv
    add_external([this] () { this->template invoke_internal<logic_error>([]() { throws_logic_error(); }); });

    add_external([this] () { this->template invoke_internal<runtime_error>([]() { throws_runtime_error(); }); });
}   //                       ^^^^^^^^^^^^^^

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

Обычно это должно происходить только с зависимыми типами / вложенными шаблонами и может быть решено с помощью template непосредственно перед рассматриваемым шаблоном (как показано), который сообщает компилятору, что шаблон следует (duh),Нам нужно this-> до этого, хотя, потому что иначе это будет выглядеть как явная реализация, которая сама по себе будет неправильной:

template Foo<int>; // explicitly instantiate the Foo class template for int

Теперь.как ни странно, эта проблема также возникает здесь, и я могу только согласиться с @sehe, что это похоже на ограничение компилятора.

3 голосов
/ 22 июня 2011

Это выглядело бы как ограничение компилятора. Он прекрасно компилируется на gcc 4.6 с --std = c ++ 0x

На случай, если кто-то еще захочет попробовать, я проделал некоторую работу, чтобы на самом деле скопировать / вставить это в надлежащий компилируемый код:

#include <vector>
#include <functional>
#include <stdexcept>
using namespace std;

class base
{
    public:

        void invoke_externals()
        {
            for (auto it = funcs_.begin(); it != funcs_.end(); ++it)
            {
                (*it)();
            }
        }

    protected:

        void add_external(function<void(void)> func)
        {
            funcs_.push_back(func);
        }

        template <typename T>
            void invoke_internal(function<void(void)> func)
            {
                try
                {
                    func();
                }
                catch (const T&)
                {
                }
                catch (...)
                {
                }
            }

        vector<function<void(void)>> funcs_;
};

void throws_logic_error()   { throw logic_error("");   }
void throws_runtime_error() { throw runtime_error(""); }

class derived : public base
{
    public:

        derived()
        {
            add_external([this] () { invoke_internal<logic_error>([]() { throws_logic_error(); }); });

            auto g = [this] () { invoke_internal<runtime_error>([]() { throws_runtime_error(); }); };
            add_external(g);
        }
};

int main(int, char*[])
{
    derived().invoke_externals();

    return 0;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...