Есть ли способ вызвать функцию инициализации только при создании экземпляра определенного шаблона класса (специализации)?

Я разрабатываю оболочку для различных вычислительных функций. Некоторые базовые бэкенды требуют, чтобы некоторые функции инициализации вызывались до того, как будут сделаны какие-либо другие вызовы API. Я мог бы использовать некоторую статическую переменную, которая инициализируется перед основной, и обернуть ее в некоторую функцию, как описано здесь, чтобы я мог поймать любые ошибки, возникшие во время инициализации.

Интересно, есть ли лучший способ справиться с этим. Обратите внимание, что никогда не будет экземпляра шаблона класса, поскольку все является либо typedef, либо статическим членом.


person rubenvb    schedule 29.04.2015    source источник
comment
Название совершенно неправильное, оно не описывает вопрос.   -  person Mykhaylo Kopytonenko    schedule 29.04.2015
comment
Почему бы не делегировать статические члены экземпляру singleton, который будет инициализирован при первом использовании (и который может правильно обрабатывать ошибки?)   -  person Nim    schedule 29.04.2015


Ответы (1)


Чтобы решить проблему инициализации API только для некоторых специализаций и его инициализации только один раз, я бы сделал что-то вроде этого:

#include <iostream>

template <typename T>
struct Wrapper
{
    // class who will be statically instantiated
    struct CtorClass
    {
        CtorClass()
        {
            std::cout << "Init\n";
        }
    };

    static CtorClass static_ctor;

    static void compute1(){}
    static void compute2(){}

};

// definition for template static member cons
template <typename T>
typename Wrapper<T>::CtorClass Wrapper<T>::static_ctor;

struct NeedInit{};

// you will have to use static_ctor in every funcition of the
template <>
void Wrapper<NeedInit>::compute1()
{
    static_ctor;
}

template <>
void Wrapper<NeedInit>::compute2()
{
    static_ctor;
}

int main()
{
    Wrapper<int>::compute1();
    Wrapper<int>::compute2();
    Wrapper<NeedInit>::compute1();
    Wrapper<NeedInit>::compute2();
}

К сожалению, таким образом вам придется использовать static_ctor в каждой специализации функций, принадлежащих классу Wrapper<NeedInit>. Но вам не нужно проверять, что инициализация уже была вызвана.

Затем вы можете поймать ошибки, как вы сказали.

person Paolo M    schedule 29.04.2015
comment
Верно, это один из способов, который я наполовину придумал. Это влечет за собой штраф во время выполнения, хотя и намного меньший штраф, чем если бы пользователь был вынужден вызвать функцию инициализации. Как std::cout справляется с этим? Я думал, что у него есть какой-то механизм инициализации stdio, когда он используется. - person rubenvb; 29.04.2015
comment
@rubenvb Ммм, не знаю, как cout обрабатывает инициализацию ввода-вывода. Может быть, это выполняется всякий раз, когда включен ‹iostream›, даже если cout не используется? - person Paolo M; 30.04.2015