jeudi 26 mai 2016

C++11 Check two sets of variadic template arguments match

This question relates to an earlier one I asked regarding implementing something akin to Qt's signal/slots in C++11.

Consider the following (very simplified signal dispatcher, that in this example does nothing of any use, it's just to demonstrate the pattern/problem):

template< typename... TYPES >
class Signal
{
public:
    Signal()  = default;
    ~Signal() = default;

    template< typename... PARAMETERS >
    void broadcast( PARAMETERS &&... p )
    {
        // static_assert to confirm PARAMETERS can map to TYPES
    }
};

This works well enough, but there's some unwanted type conversion going on in practice. e.g.;

// acceptable use.
Signal< int, unsigned, float, char >().broadcast(   1, 2u, 0.f, 'a' );

// should fail compilation, first parameter is a float, 4th is an int.
Signal< int, unsigned, float, char >().broadcast( 0.f,  0, 0.f,   0 );

// acceptable use, first parameter is const, but it's convertible.
const int   i  = 3;
Signal< int, unsigned, float, char >().broadcast(  i, 2u, 0.f, 'a');

// acceptable use, first parameter is const &, but it's convertible.
const int & j = i;
Signal< int, unsigned, float, char >().broadcast(  j, 2u, 0.f, 'a');

There should be no silent float to int conversion. Conversion of const/const & in this instance should be possible (the format of TYPES should not have const or & as all data should be passed by value).

I'd like to prevent compilation where such unwanted type conversion happens. I thought to wrap up both TYPES and PARAMETERS in tuples, iterate over the tuple and confirm that each type in a given tuple parameter index matches (including using std::decay), but then I couldn't see a way to do that at compile time so that it could go in a static_assert.

For reference, compilers of choice are clang (latest on OS X 7.3 (clang-703.0.31)) and vc14.

Is what I want to do possible and, if so, can anyone offer any pointers?

Aucun commentaire:

Enregistrer un commentaire