Yucel_K
Yucel_K

Reputation: 698

limiting template arguments to only set of classes that have different constructor signature

I have a number of classes in my project that acts as a message. and also have a template function that takes a class type and do some work with it.

template <typename T>
static int SendBroadcastMsg(T msg)
{
    //....do something
    return 0; //return an int result once finished.
}

in my main, I have a bunch of messages sent using this template. but I want to limit the template arguments to only Message and AnotherMsg types.

SendBroadcastMsg<Message>(1); //should be valid
SendBroadcastMsg<AnotherMsg>({ true, 2 }); //should be valid
SendBroadcastMsg<NotAMsg>(1);//shoud NOT be valid.
SendBroadcastMsg<NotAMsg>({ false, 1 });// should NOT be valid.

I found some answers here but I can't seem to get it working. I'm suspecting its perhaps due to the constructors of these classes have parameters in it but I'm not sure how to deal with it. Any help would be appreciated.

Full code :

#include <iostream>
#include <memory>
#include <vector>
struct Message
{
    Message( const int val) : Val(val) {}
    int Val;
};

struct AnotherMsg
{
    AnotherMsg( const bool  con, int val) : Cond(con), Val(val){}
    bool Cond;
    int Val;
};

struct NotAMsg
{
    NotAMsg(const int val) : Val(val),  Cond(false){}
    NotAMsg(const bool con, int val) : Cond(con), Val(val){}
    bool Cond;
    int Val;
};


//template function wrapper.
template <typename T>
static int SendBroadcastMsg(T msg)
{
    //....do something
    return 0; //return an int result once finished.
}

template <typename T>
constexpr bool is_ValidMsg()
{
    return std::is_same<T, Message>(const int) || std::is_same<T, AnotherMsg>(const bool, int);
}



template <typename T>
using common_byfunc = typename std::conditional<is_ValidMsg<T>(), NotAMsg, T>::type;


static_assert(std::is_same <common_byfunc<Message>, NotAMsg>(), "");
static_assert(std::is_same <common_byfunc<AnotherMsg>, NotAMsg>(), "");

int main()
{
    SendBroadcastMsg<Message>(1);
    SendBroadcastMsg<AnotherMsg>({ true, 2 });
    SendBroadcastMsg<NotAMsg>(1);//shoud not be valid.
    SendBroadcastMsg<NotAMsg>({ false, 1 });// should not be valid.
    return 0;
}

Upvotes: 1

Views: 91

Answers (1)

max66
max66

Reputation: 66240

The correct syntax (a possible correct syntax) is

template <typename T>
constexpr bool is_ValidMsg()
{
    return std::is_same<T, Message>::value || std::is_same<T, AnotherMsg>::value;
}

I mean... I don't know what do you mean with

std::is_same<T, Message>(const int)

and

std::is_same<T, AnotherMsg>(const bool, int)

but they are wrong.

If you want avoid that SendBroadcastMsg() is compiled with non message types, you can use is_ValidMsg() to SFINAE enable/disable it.

There are many ways; by example

template <typename T>
static std::enable_if_t<is_ValidMsg<T>(), int> SendBroadcastMsg(T msg)
{
    //....do something
    return 0; //return an int result once finished.
}

But remember to define is_ValidMsg() before SendBroadcasMsg()

Another possible solution pass through the use of is_ValidMsg() in a simple static_assert() inside SendBroadcastMsg()

template <typename T>
static int SendBroadcastMsg(T msg)
{
   static_assert( is_ValidMsg<T>(), "!" );

    //....do something
    return 0; //return an int result once finished.
}

Upvotes: 1

Related Questions