2015-07-05 2 views
2

Имея следующий пример:VARIADIC шаблоны пакет одного шаблонного класса

/* Signal Container */ 
template <typename Ret> class Signal; 

template <typename Ret, typename... Args> 
class Signal< Ret (Args...) > 
{ 
    /* Following Implementation... */ 
}; 

/* Emitter Type */ 
template < template <typename Ret, typename... Args> Signal< Ret (Args...) > ... Sig> 
class Emitter 
{ 
    // using Signals = std::tuple<Sig...>; 

    /* Following Implementation... */ 
}; 

/* Signals */ 
using Signal_A = Signal<void()>; 
using Signal_B = Signal<void(int)>; 
using Signal_C = Signal<void(int, float)>; 

/* Desired Usage */ 
class MyType : public Emitter<Signal_A, Signal_B, Signal_C> 
{ 

}; 

Я хотел бы иметь возможность наследовать от Emitter типа, который принимает 1 (0?) Или более параметров шаблона типа Signal (и только Signal). Signal - это шаблонный тип, и его определение отличается от каждого типа, переданного в пакет аргументов Emitter.

Я попробовал текущий подход к MinGW, но я получаю эти сообщения об ошибках, и я немного потерял:

/* Line: template < template <typename Ret, typename... Args> Signal< Ret (Args...) > ... Sig> */ 
main.cpp|15|error: expected 'class' before 'Signal'| 


/* Line: template < template <typename Ret, typename... Args> Signal< Ret (Args...) > ... Sig> */ 
main.cpp|15|error: expected '>' before '<' token| 


/* Line: class MyType : public Emitter<Signal_A, Signal_B, Signal_C> */ 
main.cpp|29|error: wrong number of template arguments (3, should be 1)| 


/* Linne: class Emitter */ 
main.cpp|16|error: provided for 'template<template<class Ret, class ... Args> class Signal> class Emitter'| 

Если кто-то может уточнить это или предоставить рабочее решение, которое я был бы благодарен.

Доступные Составители: MinGW GCC 4.9.2 (также 5.1.0)

ответ

2

Вы не можете делать то, что хотите на C++ 11 или C++ 14, простым способом. Концепции могут дать нам что-то, но теперь ваши аргументы шаблона должны быть либо типом, либо шаблоном класса, либо значением. В вашем случае, вы хотите пакет сигналов, который может быть определен только как:

template <typename... Sigs> 
class Emitter; 

В классе, вы можете использовать static_assert, чтобы убедиться, что все они Signal S:

static_assert(all_true<is_signal<Sigs>::value...>::value, "Emitter must use only Signals"); 

Вам нужно написать характеристику типа для is_signal и предоставить metafunction для all_true. Один из примеров последних можно найти: here

+0

спасибо. Это то, что я на самом деле закончил. Все, что я хотел, состояло в простой проверке полученных типов в пакете шаблонов. –

1

Вы не должны соответствовать всем внутренним типам Signal в шаблоне класса Emitter. Вы просто должны указать, что это шаблон, принимающий параметры. После этого вам нужно будет вернуться к минимальному количеству Signal<T>, которое вы можете разрешить в своем приложении. Предположим, что минимум - один, вот решение.

/* Signal Container */ 
template <typename Ret> 
class Signal; 

template <typename Ret, typename... Args> 
class Signal<Ret(Args...)> {}; 

/* Emitter Type */ 
template <typename... Args> 
class Emitter; 

template <typename T> 
class Emitter<Signal<T> > { 
    // definition of class with single signal 
}; 

template <typename T, typename... Args> 
class Emitter<Signal<T>, Args...> { 
    // definition of class with MORE THAN one signal 
}; 

/* Signals */ 
using Signal_A = Signal<void()>; 
using Signal_B = Signal<void(int)>; 
using Signal_C = Signal<void(int, float)>; 

/* Desired Usage */ 
class MyType : public Emitter<Signal_A, Signal_B, Signal_C> {}; 

int main() { 
    MyType x; 
} 
0

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

#include <iostream> 

/* Signal Container */ 
template <typename Ret> class Signal; 

template <typename Ret, typename... Args> 
class Signal< Ret (Args...) > 
{ 
    /* Following Implementation... */ 
}; 

namespace { 
    /* Signal Type Traits */ 
    template < typename T > 
    struct IsSignal { static constexpr bool Value = false; }; 

    template < typename T > 
    struct IsSignal< Signal<T> > { static constexpr bool Value = true; }; 

    /* Signal Validation */ 
    template < bool V, typename... Args > 
    struct AreSignals 
    { 
     static constexpr bool Value = V; 
    }; 

    template < bool V, typename T, typename... Args > 
    struct AreSignals< V, T, Args... > 
    { 
     static constexpr bool Value = AreSignals< V && IsSignal<T>::Value, Args... >::Value; 
    }; 

} 

/* Emitter Type */ 
template < typename... Args > 
class Emitter 
{ 
    // Block unsupported signals 
    static_assert(AreSignals<true, Args...>::Value, "Unsupported signal type"); 

    using Signals = std::tuple<Args...>; 

    /* Following Implementation... */ 
}; 

using Signal_A = Signal<void()>; 
using Signal_B = Signal<void(int)>; 
using Signal_C = Signal<void(int, float)>; 

class MyType : public Emitter<Signal_A, Signal_B, Signal_C> 
{ 

}; 

int main(int argc, char **argv) 
{ 
    std::cout << AreSignals<true, Signal_A, Signal_B, Signal_C>::Value << "\n"; // 1 (true) 

    std::cout << AreSignals<true, Signal_A, int, Signal_B, Signal_C>::Value << "\n"; // 0 (false) 

    return EXIT_SUCCESS; 
}