Отключение / скрытие функций в шаблоне на основе констант времени компиляции - PullRequest
5 голосов
/ 02 ноября 2011

Можно ли условно скрыть или отключить функции в классе шаблона, используя константы времени компиляции?

Представьте себе следующий класс:

template<size_t M, size_t N>
class MyClassT
{
    // I only want this function available if M == N, otherwise it is illegal to call
    static MyClassT<M, N> SomeFunc()
    {
        ...
    }
}


MyClassT<2,2>::SomeFunc(); // Fine
MyClassT<3,2>::SomeFunc(); // Shouldn't even compile

Ответы [ 2 ]

8 голосов
/ 02 ноября 2011

Использовать частичную специализацию и наследование:

// Factor common code in a base class
template <size_t n, size_t m>
class MyClassTBase
{
    // Put here the methods which must appear
    // in MyClassT independantly of n, m
};

// General case: no extra methods
template <size_t n, size_t m>
class MyClassT : MyClassTBase<n, m>
{};

// Special case: one extra method (you can add more here)
template <size_t n>
class MyClassT<n, n> : MyClassTBase<n, n>
{
    static MyClassT<n, n> SomeFunc()
    {
        ...
    }
};

Другой вариант - использовать SFINAE: std::enable_if или его вариант:

template <size_t n, size_t m>
class MyClassT
{
    template <typename EnableIf = char>
    static MyClassT<n, m> SomeFunc(EnableIf (*)[n == m] = 0)
    {
        ...
    }
};

тем более многословной альтернативой (но менее удивительной, если вы не знаете о SFINAE и указателе на массивы) является

template <size_t n, size_t m>
class MyClassT
{
    template <typename Dummy = char>
    static MyClassT<n, m>
    SomeFunc(typename std::enable_if<n == m, Dummy>::type * = 0)
    {
        ...
    }
};

Как правило, я предпочитаю подходы SFINAE, в которых есть одна или две функции-члена для включения или отключения. Как только это становится более сложным, я предпочитаю технику частичной специализации.

РЕДАКТИРОВАТЬ: Код SFINAE был неправильным, так как не было шаблонных функций. Исправлено.

4 голосов
/ 02 ноября 2011

Идеальный способ предоставления специализаций - использование шаблонных специализаций. Вы можете переместить все основные функции в базовый класс:

template< size_t M, size_t N >
class basic_class{ ... };

template< size_t M, size_t N >
class my_class : basic_class< M, N > { ... };


template< size_t M >
class my_class< M, M > : basic_class< M, N > { ... };

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

template< typename Dummy = int >
typename std::enable_if< M == N, my_class >::type some_func( Dummy* = 0 );
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...