недопустимое использование неполного типа

Я думаю, что следующий вспомогательный метод также может решить проблему.

private TResult InvokeAsyncFuncSynchronously<TResult>(Func< Task<TResult>> func)
    {
        TResult result = default(TResult);
        var autoResetEvent = new AutoResetEvent(false);

        Task.Run(async () =>
        {
            try
            {
                result = await func();
            }
            catch (Exception exc)
            {
                mErrorLogger.LogError(exc.ToString());
            }
            finally
            {
                autoResetEvent.Set();
            }
        });
        autoResetEvent.WaitOne();

        return result;
    }

Может использоваться следующим образом:

InvokeAsyncFuncSynchronously(Service.GetCustomersAsync);
53
задан seanhodges 16 March 2009 в 21:20
поделиться

5 ответов

Причина состоит в том, что при инстанцировании шаблона класса, все его объявления (не определения) его функций членства инстанцируют также. Шаблон класса инстанцируют точно, когда полное определение специализации требуется. Это имеет место, когда это используется в качестве базового класса, например, в качестве в Вашем случае.

Поэтому то, что происходит, - то, что A<B> инстанцирован в [1 113]

class B : public A<B>

, в котором точка B еще не является полным типом (это после закрывающей фигурной скобки определения класса). Однако A<B>::action объявление требует B быть завершенным, потому что это сканирования в пределах него:

Subclass::mytype

то, Что необходимо сделать, задерживает инстанцирование к некоторой точке, в которой B завершено. Один способ сделать это состоит в том, чтобы изменить объявление action для создания этого членским шаблоном.

template<typename T>
void action(T var) {
    (static_cast<Subclass*>(this))->do_action(var);
}

Это все еще безопасно с точки зрения типов, потому что, если var не имеет правильного типа, передавая var к [1 111], перестанет работать.

62
ответ дан Johannes Schaub - litb 7 November 2019 в 18:43
поделиться

Можно обойти это при помощи класса черт:
Это требует, чтобы Вы настроили specialsed класс черт для каждого фактического класса, который Вы используете.

template<typename SubClass>
class SubClass_traits
{};

template<typename Subclass>
class A {
    public:
        void action(typename SubClass_traits<Subclass>::mytype var)
        {
                (static_cast<Subclass*>(this))->do_action(var);
        }
};


// Definitions for B
class B;   // Forward declare

template<> // Define traits for B. So other classes can use it.
class SubClass_traits<B>
{
    public:
        typedef int mytype;
};

// Define B
class B : public A<B>
{
    // Define mytype in terms of the traits type.
    typedef SubClass_traits<B>::mytype  mytype;
    public:

        B() {}

        void do_action(mytype var) {
                // Do stuff
        }
};

int main(int argc, char** argv)
{
    B myInstance;
    return 0;
} 
24
ответ дан Martin York 7 November 2019 в 18:43
поделиться

Не точно, что Вы спрашивали, но можно сделать действие шаблонной функцией членства:

template<typename Subclass>
class A {
    public:
        //Why doesn't it like this?
        template<class V> void action(V var) {
                (static_cast<Subclass*>(this))->do_action();
        }
};

class B : public A<B> {
    public:
        typedef int mytype;

        B() {}

        void do_action(mytype var) {
                // Do stuff
        }
};

int main(int argc, char** argv) {
    B myInstance;
    return 0;
}
1
ответ дан John Dibling 7 November 2019 в 18:43
поделиться

Необходимо использовать указатель или ссылку, поскольку надлежащий тип не известен в это время, компилятор не может инстанцировать его.

Вместо этого попытка:

void action(const typename Subclass::mytype &var) {
            (static_cast<Subclass*>(this))->do_action();
    }
0
ответ дан Andreas Magnusson 7 November 2019 в 18:43
поделиться

Вы происходите B от A<B>, таким образом, первая вещь, которую делает компилятор, как только это видит определение класса B, состоит в том, чтобы попытаться инстанцировать A<B>. Чтобы сделать это, этому нужно к известному B::mytype для параметра action. Но так как компилятор находится только в процессе выяснения фактического определения B, это еще не знает этот тип, и Вы получаете ошибку.

Один путь вокруг этого, должен был бы объявить тип параметра как другой шаблонный параметр, вместо внутренней части производный класс:

template<typename Subclass, typename Param>
class A {
    public:
        void action(Param var) {
                (static_cast<Subclass*>(this))->do_action(var);
        }
};

class B : public A<B, int> { ... };
2
ответ дан sth 7 November 2019 в 18:43
поделиться
Другие вопросы по тегам:

Похожие вопросы: