Избежание ненужных шаблонов в свободном интерфейсе - PullRequest
1 голос
/ 02 января 2012

У меня есть класс с некоторыми необязательными параметрами шаблона:

struct option1_default_t {};
struct option2_default_t {};

template <typename T, 
          typename option1_t = option1_default_t, 
          typename option2_t = option2_default_t>
class foo
{
public:
    foo(option1_t option1 = option1_t(), option2_t option2 = option2_t());

    void run();
};

И следующий свободный интерфейс для их указания:

template <typename T, typename option1_t, typename option2_t>
struct foo_runner
{
    option1_t option1_;
    option2_t option2_;

    template <typename new_option1_t>
    foo_runner<T, new_option1_t, option2_t> option1(new_option1_t new_option1)
    {
        return foo_runner<T, new_option1_t, option2_t>{new_option1, option2_};
    }

    template <typename new_option2_t>
    foo_runner<T, option1_t, new_option2_t> option2(new_option2_t new_option2)
    {
        return foo_runner<T, option1_t, new_option2_t>{option1_, new_option2};
    }

    void run()
    {
        foo<T, option1_t, option2_t> f(option1_, option2_);
        f.run();
    }
};

template <typename T>   
foo_runner<T, option1_default_t, option2_default_t> make_foo()
{
    return foo_runner<T, option1_default_t, option2_default_t>();
}

Вот примеркак используется свободный интерфейс:

struct my_option1_t { ... };
struct my_option2_t { ... };

int main()
{
    make_foo<int>()
        .option1(my_option1_t(...))
        .option2(my_option2_t(...))
        .run();
}

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

Проблема с этим свободным интерфейсом состоит в том, чтоненужные шаблоны экземпляров.Например, в приведенном выше примере трижды создаются foo: foo<int, option1_default_t, option2_default_t>, foo<int, my_option1_t, option2_default_t> и, наконец, foo<int, my_option1_t, my_option2_t>, который мне нужен.

Это проблематично, поскольку foo являетсябольшой класс и создание его экземпляров - это дорогое время компиляции.

Есть ли способ, которым я мог бы изменить реализацию беглого интерфейса , не меняя способ использования интерфейса , чтобы foo был толькоОдин раз был создан экземпляр с последними аргументами?

Обратите внимание, что требование, чтобы интерфейс не изменялся - то есть тот же самый код, который я дал в качестве примера использования свободного интерфейса, продолжает работать без изменений -ключ здесь.Без этого требования я мог бы легко переписать свободный интерфейс, чтобы создать экземпляр foo только один раз (например, я мог бы изменить интерфейс на что-то вроде run_foo(make_foo<int>().option1(...).option2(...))).

1 Ответ

1 голос
/ 03 января 2012

Я не думаю, что существует несколько экземпляров foo (как было указано в комментарии MSalters).Если вы хотите проверить это, вы можете создать специализации foo для параметров по умолчанию, что приведет к ошибке при их создании.Очевидно, что это не было бы хорошо для реальной рабочей версии, но это доказало бы, что не существует множественных экземпляров.

Как только вы убедились, что множественные экземпляры foo действительно не являются проблемой, возникает вопрос: как улучшить время компиляции для шаблонного кода?Ответ, как правило, состоит в том, чтобы разделить код на помощники, которые зависят от меньшего количества аргументов шаблона (если они есть).Это что-то вроде боли, но может оказать сильное воздействие.Также может быть полезно избегать создания экземпляров во всех единицах перевода часто используемых шаблонов.В C ++ 2011 вы можете использовать внешние шаблоны в сочетании с явными экземплярами.В C ++ 2003 вам придется специализировать код, который вы хотите предварительно создать.

...