Конфликт идентичных баз при оптимизации нескольких пустых элементов - PullRequest
0 голосов
/ 14 февраля 2020

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

template<class Callback1, class Callback2>
struct S: Callback1, Callback2
{
    S(Callback1 c1, Callback2 c2): Callback1(c1), Callback2(c2) {}
    void Method()
    {
        Callback1::operator()();
        Callback2::operator()();
    }
    int field;
};
struct Functor {};
struct Functor2 {};
static_assert(sizeof(S<Functor, Functor2>) == sizeof(int));

Проблема этого решения в том, что я не могу создать что-то вроде S<Functor, Functor>. Когда эти два аргумента имеют одинаковый тип, я получаю ошибку компилятора о двух идентичных родителях. Как лучше всего обойти эту проблему?

Редактировать: Всегда должно быть два экземпляра обратных вызовов, даже если они одного типа. Любой из этих обратных вызовов может быть пустым или не пустым (с состоянием), но случаи, когда любой из них или оба пусты пусты, должны быть оптимизированы.

Ответы [ 3 ]

1 голос
/ 15 февраля 2020

Единственный способ задействовать множественное наследование от одной и той же базы - это go что-то вроде;

template <class Callback> struct FirstBase : Callback {};
template <class Callback> struct SecondBase : Callback {};

struct Functor1 {};
struct Functor2 {};

template<class Callback1, class Callback2> struct S: FirstBase<Callback1>, SecondBase<Callback2> {int field;};
1 голос
/ 15 февраля 2020

Прямое решение для решения этой проблемы заключается в специализации.

template<class Functor>
struct S<Functor, Functor> : Functor {
  int field;
};

Если это вызывает слишком много повторений, вы можете повторно использовать код для версии с двумя функторами, введя специальный «нулевой функтор» .

struct NullFunctor { /* Whatever implementation makes sense in your domain */ };

template<class Functor>
struct S<Functor, Functor> : S<Functor, NullFunctor> {};

В качестве альтернативы, если ваша цель - разрешить клиентскому коду использовать S с одним или двумя разными функторами, вы можете специализироваться на пакете параметров шаблона.

template<class ...Functors>
struct S;

template<class Functor>
struct S<Functor> : Functor {
};

template<class Functor1, class Functor2>
struct S<Functor1, Functor2> : Functor1, Functor2 {
};

template<class Functor> 
struct S<Functor, Functor>; // Same functor used twice. 
0 голосов
/ 15 февраля 2020

Это было удивительно сложно. Следующий код позволяет наследовать от произвольного списка типов, и каждый тип списка будет использоваться в качестве базового ровно один раз:

#include <type_traits>

template<class T, class... Ts>
struct is_among;

template<class T, class... Ts>
struct is_among<T, T, Ts...> : std::true_type {
    using value_t = T;
};

template<class T, class U, class... Ts>
struct is_among<T, U, Ts...> : is_among<T, Ts...> {};

template<class T>
struct is_among<T> : std::false_type{};

template<class SFINAE, class... Ts>
struct inherit_once;

template<class T, class... Ts>
struct inherit_once<std::enable_if_t<!is_among<T, Ts...>::value>,T, Ts...> : inherit_once<void, Ts...>, T {};

template<class T, class... Ts>
struct inherit_once< std::enable_if_t<is_among<T, Ts...>::value>, T, Ts...> : inherit_once<void, Ts...> {};

template<>
struct inherit_once<void>{};

struct A{
    void operator()(int){}
    };

struct B : inherit_once<void, A, A> {
    int i;
};
int main(){
    static_assert(sizeof(int) == sizeof(B));
    B b;
    b(1);
}

Редактировать: с несколькими экземплярами:

#include <utility>

template<class F, size_t id>
struct id_wrap: F {};

template<class id_seq, class... Funcs>
struct OptHelper;

template<class... Funcs, size_t... ids>
struct OptHelper<std::index_sequence<ids...>, Funcs...> : id_wrap<Funcs, ids>... {};

template<class... Funcs>
struct Opt: OptHelper<std::index_sequence_for<Funcs...>, Funcs...> {int i;};

struct Functor {
    void operator()(int) {}
};

int main(int argc, char *argv[])
{
    static_assert(sizeof(Opt<Functor,Functor>) == sizeof(int));
    Opt<Functor> f{};
    f(1);
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...