Использование enable_if для необязательного добавления члена структуры

Учитывая этот шаблон:

template <class A>
struct Something {
    ... // members common to all template instantiations for all A types 
    SpecialType member; // but not this - I want this to be conditional...
}

... Я хочу использовать "enable_if", чтобы член SpecialType существовал условно; то есть только тогда, когда шаблон создан с типами A=SpecialCase1 или SpecialCase2. Во всех остальных случаях я хочу, чтобы элемент SpecialType отсутствовал.

Если вам интересно, почему, речь идет об оптимизации, то есть о том, чтобы не нести бесполезную полезную нагрузку в структуре. Я новичок в метапрограммировании шаблонов, но я понимаю, что мне нужно как-то "enable_if" и два "is_same" - хотя не уверен, как именно...

РЕДАКТИРОВАТЬ: Выполнение этого с помощью общего С++ (т.е. без специфики Boost) было бы плюсом.


person ttsiodras    schedule 13.04.2012    source источник


Ответы (4)


Хорошо: используйте базовый класс.

struct Empty {};

struct SpecialTypeCnt { SpecialType member; };

template <typename A>
struct Something: if_< /* cond */ , SpecialTypeCnt, Empty>::type {
};

Где if_ определяется как:

template <typename, typename, typename E> struct if_ { typedef E type; };

template <typename T, typename E>
struct if_<std::true_type, T, E> { typedef T type; };

(Вы также можете специализироваться на логическом значении)

Теперь, конечно, вам нужно правильно выразить свое состояние.


Сказав это, вы, вероятно, не должны использовать только struct. Вместо этого вы должны использовать class, который предоставляет операции, которые необходимо применить к member. Затем вы предоставляете class Null с поведением по умолчанию и class SomeType с поведением, характерным для member.

В противном случае вы будете переписывать условие везде, где вам нужно «возможно» изменить member, и это очень быстро надоест.

person Matthieu M.    schedule 13.04.2012
comment
if_ обычно называют std::conditional. - person Kerrek SB; 13.04.2012
comment
@KerrekSB: Ах, спасибо, боюсь, я немного старожил. В Boost MPL это было if_ :) В новых библиотеках C++11 я пока особо не копался :/ - person Matthieu M.; 13.04.2012

Вам не нужен enable_if для этого. Специализируйте свою структуру для особых случаев и оставьте реализацию по умолчанию для остальных:

template <class A>
struct Something
{
  // your default implementation
};

template <>
struct Something<SpecialCase1>
{
  // your SpecialCase1 implementation
};

template <>
struct Something<SpecialCase2>
{
  // your SpecialCase2 implementation
};
person bobah    schedule 13.04.2012
comment
Это приведет к повторению всех общих полей и функций-членов — я хочу этого избежать (СУХОЙ). - person ttsiodras; 13.04.2012
comment
@ttsiodras - используйте композицию или наследование и делайте то, что я предложил для члена или базового класса - person bobah; 13.04.2012

Чтобы не дублировать общие члены:

Определите класс BaseSomething:

 template <class A>
        struct BaseSomething {
            ... // members common to all template instantiations for all A types 
                };

Определите класс SpecialSomething:

template <class A>
            struct SpecialSomething {
                SpecialType member;
                ...//SpetialType related functionality
                    };

Определить что-то класс:

template <class A>
            struct Something :public BaseSomething<A>{

                    };



  template<>
    struct Something<SpecialCase1>:public BaseSomething<A>{
                    SpecialSomething<SpecialCase1> special;
                        };


template<>
struct Something<SpecialCase2>:public BaseSomething<A>{
                SpecialSomething<SpecialCase2> special;
                    };
person Yakov    schedule 13.04.2012
comment
Это самое близкое к тому, что мне нужно, но, конечно, это гораздо более многословно, чем одна строка enable_if... - person ttsiodras; 13.04.2012
comment
Если многословие не работает для вас, вам следует хотя бы тщательно изучить свой выбор использования языка C++. Иногда это может быть очень многословно. - person Mark B; 13.04.2012

На это уже ответил Матье М. Однако несколько более идиоматическим и элегантным решением было бы сделать следующее:

struct OptionalMembers { SpecialType member; };

template <typename T>
    class Something: public conditional_t<is_same<T, SpecialCase>, OptionalMembers, tuple<>> {
};

В этом примере показано, как добавлять необязательные элементы, только если параметр шаблона имеет тип SpecialCase.

person chaitan94    schedule 13.07.2020