【问题标题】:limiting template arguments to only set of classes that have different constructor signature将模板参数限制为仅具有不同构造函数签名的类集
【发布时间】:2019-03-29 11:53:59
【问题描述】:

我的项目中有许多类充当消息。 并且还有一个模板函数,它接受一个类类型并使用它做一些工作。

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

在我的主要内容中,我有一堆使用此模板发送的消息。但我想将模板参数限制为仅 MessageAnotherMsg 类型。

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.

我找到了一些答案here,但我似乎无法让它工作。我怀疑这可能是因为这些类的构造函数中有参数,但我不知道如何处理它。任何帮助将不胜感激。

完整代码:

#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;
}

【问题讨论】:

    标签: c++ c++11 templates c++14 sfinae


    【解决方案1】:

    正确的语法(可能是正确的语法)是

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

    我的意思是……我不知道你是什么意思

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

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

    但他们错了。

    如果您想避免 SendBroadcastMsg() 编译为非消息类型,您可以使用 is_ValidMsg() 来启用/禁用 SFINAE。

    有很多方法;举例

    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.
    }
    

    但记得在SendBroadcasMsg()之前定义is_ValidMsg()

    另一种可能的解决方案是在SendBroadcastMsg() 内部的简单static_assert() 中使用is_ValidMsg()

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

    【讨论】:

    • 啊,我明白了。我想我必须让编译器知道在为std::is_same. 构建类的过程中它需要什么类型,我进行了更改,并且现在可以编译了。但我确信某处还有其他错误,因为编译器仍然为SendBroadcastMsg&lt;NotAMsg&gt;(1);SendBroadcastMsg&lt;NotAMsg&gt;({ false, 1 }); 编译
    • @Yucel_K - 你已经定义了is_ValidMsg(),但你还没有使用它来启用/禁用SFINAE SendBroadcastMsg()。答案得到改善。
    • 你先生!是我的英雄。它工作得很好。只有一个问题。 (也许您可能想编辑您的答案)我不得不将 myNotAMsg 结构更改为空。当我将它与一些类成员和构造函数一起使用时,它无法选择错误的模板参数。那是什么原因呢?
    • @Yucel_K - 我不知道;您应该准备一个完整的(但最少的)示例来重现该问题。我只是在NotAMsg 中看到了一个问题:在第一个构造函数中,您首先初始化Val,然后再初始化Cond,其中首先定义Cond。错误的。您必须按照定义的顺序初始化成员。
    • 哦,我明白了。如果我能接受这一点而不是我肯定会接受的话,那是有道理的。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-08-04
    • 1970-01-01
    • 1970-01-01
    • 2011-07-05
    • 1970-01-01
    • 2015-06-17
    相关资源
    最近更新 更多