首页 \ 问答 \ 在模板函数参数之间强制实现所需的关系(Enforcing desired relationship between template function parameters)

在模板函数参数之间强制实现所需的关系(Enforcing desired relationship between template function parameters)

我正在努力改进内部消息库,旨在在我们的应用程序内部发送消息,以及外部消费者。 消息由MessageTypeenum class )和一些数据( struct )组成。 每个MessageType::对应于特定的数据类型(例如, MessageType::TypeA将始终包含Foo )。 但是,多种消息类型可以使用相同的结构(例如, MessageType::TypeM也可以使用Foo )。

我们有一个可以发送消息的类。 我们之前的消息发送者类实现为每种类型定义了一个方法:

SendMessageTypeA(Foo data)
SendMessageTypeB(Bar data)
SendMessageTypeM(Foo data)

当有大量消息时,这可能导致大量代码重复(方法体基本相同,但不同的参数类型除外)。

我已经实现了一个新方法:

template<typename structType>
void Send(MessageType msgType, const structType & messageData)

此单一方法可以发送任何消息,具体取决于提供的相应模板参数。 请注意, MessageType在编译时始终是已知的。

问题是这个新方法不强制MessageTypestruct之间的关系。 例如, Send<Foo>(MessageType::TypeB, data)将编译,即使MessageType::TypeB应包含Bar 。 将在运行时检测到不匹配,但我想使其成为编译时错误。

我不知道如何实现这一目标。 我考虑过:

  1. 声明所有SendMessageX()方法,并使用它们来调用Send<MessageX>() 。 这确实减少了重复,但每次定义消息时我仍然需要创建一个新方法。
  2. 试图使用static_assert来捕捉不匹配。 我不确定如何将MessageType映射到他们想要的struct
  3. 我正在咆哮错误的树

I'm working on improving an in-house messaging library, designed to send messages internally within our applications, and to external consumers. A message consists of a MessageType (enum class) and some data (struct). Each MessageType:: corresponds to a particular data type (e.g., MessageType::TypeA will always contain Foo). However, multiple message types could use the same struct (e.g., MessageType::TypeM could also use Foo).

We have a class that can send messages. Our previous implementation of the message sender class defines a method for each type:

SendMessageTypeA(Foo data)
SendMessageTypeB(Bar data)
SendMessageTypeM(Foo data)

When there are lots of messages, this can result in a lot of code duplication (the method body is essentially the same, with the exception of the different parameter types).

I've implemented a new method:

template<typename structType>
void Send(MessageType msgType, const structType & messageData)

This single method can send any message, depending on the appropriate template parameter being provided. Note that the MessageType is always known at compile time.

The problem is that this new method does not enforce the relationship between MessageType and struct. For example, Send<Foo>(MessageType::TypeB, data) will compile, even though MessageType::TypeB should contain Bar. The mismatch will be detected at runtime, but I'd like to make it a compile time error.

I'm not sure how to achieve this. I've considered:

  1. Declaring all the SendMessageX() methods, and use them to call Send<MessageX>(). This does reduce the duplication, but I still have to create a new method every time a message is defined.
  2. Attempting to use static_assert to catch the mismatch. I'm not sure how to map MessageTypes to their desired struct.
  3. I'm barking up the wrong tree

原文:https://stackoverflow.com/questions/39760704
更新时间:2023-07-02 12:07

最满意答案

为什么OP查询返回错误1054

返回的错误是因为从UNION的结果中分配给列的名称取自第一个SELECT。

您可以通过运行一个简单的示例来观察:

 SELECT 1 AS one 
  UNION
 SELECT 2 AS two 

该查询返回的结果集将包含单个列,分配给该列的名称将为one ,即第一个SELECT中的列名称。 这解释了为什么从查询中收到错误的原因。


返回没有匹配的行的一种方法

要返回table1col1值,该值与table2 col1列中的任何值都不匹配...

使用反连接模式的一个选项...

    SELECT t1.col1
      FROM table1 t1
      LEFT
      JOIN table2 t2
        ON t2.col1 = t1.col1
     WHERE t2.col1 IS NULL

LEFT JOIN操作返回table1中的所有行,以及table2中找到的任何“匹配”行。 “技巧”是WHERE子句中的谓词...来自table2的任何“匹配”行将在col1中具有非NULL值。 因此,如果我们排除了找到匹配项的所有行,那么我们会留下table1中没有匹配项的行。

如果我们想从table2中获取table1没有“匹配”行的行,我们可以执行相同的操作,只需翻转表的顺序即可。

如果我们组合这两个集合,但只想要一个“不匹配”值的“不同”列表,我们可以使用UNION集合运算符:

    SELECT t1.col1
      FROM table1 t1
      LEFT
      JOIN table2 t2
        ON t2.col1 = t1.col1
     WHERE t2.col1 IS NULL
     UNION 
    SELECT s2.col1
      FROM table2 s2
      LEFT
      JOIN table1 s1
        ON s1.col1 = s2.col1
     WHERE s1.col1 IS NULL

-

找出不匹配值来自哪个表

有时,我们想知道哪个查询返回了值; 我们可以通过在每个查询中包含一个文字值作为鉴别器来实现。

    SELECT 'table1' AS src
         , t1.col1
      FROM table1 t1
      LEFT
      JOIN table2 t2
        ON t2.col1 = t1.col1
     WHERE t2.col1 IS NULL
     UNION 
    SELECT 'table2' AS src
         , s2.col1
      FROM table2 s2
      LEFT
      JOIN table1 s1
        ON s1.col1 = s2.col1
     WHERE s1.col1 IS NULL
    ORDER BY 2

查找不匹配行的不同(通常性能较差)方法

一个完全不同的方法,返回一个等效的结果,将做这样的事情:

SELECT q.col1
  FROM ( SELECT 't1' AS src, t1.col1 FROM table1 t1 
          UNION
         SELECT 't2' AS src, t2.col1 FROM table2 t2
       ) q
 GROUP BY q.col1
HAVING COUNT(DISTINCT q.src) < 2
ORDER BY q.col1

(内联视图q将被“物化”为派生表,因此这种方法对于大型集合来说可能是昂贵的,并且这种方法不会利用col1上的索引来执行匹配。)另外一个小的区别是反连接方法:如果两个表中都存在NULL,则将省略col1值NULL。 除此之外,结果集是等效的。


Why Error 1054 is being returned by OP query

The error that's being returned is because the name assigned to a column from the result of a UNION is taken from the first SELECT.

You can observe this by running a simple example:

 SELECT 1 AS one 
  UNION
 SELECT 2 AS two 

The resultset returned by that query will contain a single column, the name assigned to the column will be one, the column name from the first SELECT. This explains why you are getting the error from your query.


One way to return rows with no match

To return values of col1 from table1 which do not match any value in the col1 column from table2...

one option to use an anti-join pattern...

    SELECT t1.col1
      FROM table1 t1
      LEFT
      JOIN table2 t2
        ON t2.col1 = t1.col1
     WHERE t2.col1 IS NULL

The LEFT JOIN operation returns all rows from table1, along with any "matching" rows found in table2. The "trick" is the predicate in the WHERE clause... any "matching" rows from table2 will have a non-NULL value in col1. So, if we exclude all of the rows where we found a match, we're left with rows from table1 that didn't have a match.

If we want to get rows from table2 that don't have a "matching" row in table1, we can do the same thing, just flipping the order of the tables.

If we combine the two sets, but only want a "distinct" list of "not matched" values, we can use the UNION set operator:

    SELECT t1.col1
      FROM table1 t1
      LEFT
      JOIN table2 t2
        ON t2.col1 = t1.col1
     WHERE t2.col1 IS NULL
     UNION 
    SELECT s2.col1
      FROM table2 s2
      LEFT
      JOIN table1 s1
        ON s1.col1 = s2.col1
     WHERE s1.col1 IS NULL

--

Finding out which table the non-matched value is from

Sometimes, we want to know which query returned the value; we can get that by including a literal value as a discriminator in each query.

    SELECT 'table1' AS src
         , t1.col1
      FROM table1 t1
      LEFT
      JOIN table2 t2
        ON t2.col1 = t1.col1
     WHERE t2.col1 IS NULL
     UNION 
    SELECT 'table2' AS src
         , s2.col1
      FROM table2 s2
      LEFT
      JOIN table1 s1
        ON s1.col1 = s2.col1
     WHERE s1.col1 IS NULL
    ORDER BY 2

A different (usually less performant) approach to finding non-matching rows

An entirely different approach, to returning an equivalent result, would be do something like this:

SELECT q.col1
  FROM ( SELECT 't1' AS src, t1.col1 FROM table1 t1 
          UNION
         SELECT 't2' AS src, t2.col1 FROM table2 t2
       ) q
 GROUP BY q.col1
HAVING COUNT(DISTINCT q.src) < 2
ORDER BY q.col1

(The inline view q will be "materialized" as a derived table, so this approach can be expensive for large sets, and this approach won't take advantage of indexes on col1 to perform the matching.) One other small difference between this and the anti-join approach: this will omit a col1 value of NULL if a NULL exists in both tables. Aside from that, the resultset is equivalent.

相关问答

更多
  • 你可以把所有东西都包装在一个SELECT并用你想要的别名来包装这个列。 select a as [b] -- just alias it here with whatever you want from ( select 1 as a union select 2 as b ...) result_set 但正如@威尔所说,它就是这样,不能改变这一点。 要么: 只需确保在顶部使用带有“别名”的查询,并使用包含其他查询/值的单个SELECT语句使用UNION 。 sel ...
  • 你用两个参数调用查询(比如在第一个Query中,在第二个查询中),即使它们具有相同的值..所以你必须传递两个参数 $qResults->execute([$c1, $c1]); You invoke the query with two parameters (like in the first Query and like in the second) even if they have the same value .. so you have to pass two parameters $qRes ...
  • 使用UNION和UNION ALL设置运算符,结果集的列名称在第一个SELECT中指定。 将忽略后续查询中的列名和别名。 (无法为结果集中的一列指定两个不同的别名。每个列都会分配一个名称。) 但是对于您的结果,您不一定需要UNION ALL操作。 看起来您想要在同一行上的每个状态的数量的和。 您可以使用条件聚合。 例如: SELECT i.item_name , r.item_version , SUM(IF(r.group_status=1,r.quantity,0)) AS `App ...
  • 为什么OP查询返回错误1054 返回的错误是因为从UNION的结果中分配给列的名称取自第一个SELECT。 您可以通过运行一个简单的示例来观察: SELECT 1 AS one UNION SELECT 2 AS two 该查询返回的结果集将包含单个列,分配给该列的名称将为one ,即第一个SELECT中的列名称。 这解释了为什么从查询中收到错误的原因。 返回没有匹配的行的一种方法 要返回table1中col1值,该值与table2 col1列中的任何值都不匹配... 使用反连接模式的一个选项 ...
  • 您需要为派生表提供一个别名,如下所示: SELECT * from (SELECT column1, 'table1' from table1 UNION SELECT column1, 'table2' from table2 UNION SELECT column1, 'table3' from table3) dtAlias WHERE column1 not like 'abr%' and length(column1) < 8; You need to give the de ...
  • 我不确定,但它看起来好像你想要一个视图 。 像这样定义该查询: CREATE VIEW MyMessageView AS SELECT ... FROM ... ... 现在,您可以在可以使用普通表的任何上下文中使用该视图:在FROM子句中,在JOIN子句中,作为子查询等: SELECT ... FROM MyMessageView WHERE ... ... UNION SELECT ... FROM MyMessageView WHERE ... I am answering my own que ...
  • 这是因为在WHERE之前执行SELECT并且在WHERE之前执行FROM ,因此它不能在第二个查询中使用,但它可以在第一个查询中使用。 This is because the SELECT is executed after the WHERE and the FROM is executed before the WHERE so it cannot be used in the second query but it can be used in that first query.
  • 我试过了,它对我来说很好。 但是,这是对SQL的建议更改,这可能会有所帮助。 SELECT Title AS [SAL], FirstName AS [FIRSTNAME], MiddleName AS [MIDDLENAME] FROM dbo.Employee I have tried it and it works fine for me. However, here is a suggested change to your SQL which may assist. ...
  • 您可以使用公用表表达式或子查询将FName创建为新结果集的一种虚拟列。 您可以将结果集用作一种虚拟表,并在where子句中对其进行过滤。 SELECT * FROM ( SELECT LastName , Company , Status , CASE WHEN NickName IS NULL OR NickName = '' THEN FirstName ELSE NickName END AS FName FROM d ...
  • select union构建一个结果表,一个表只能有一个列名,所以你不能为同一个列名指定不同的别名..因此sql只返回第一个 你不能通过这种方式从联合中获得不同的别名 相反,您可以使用适当的值标记每个值 $channeldetectquery = "(SELECT 'amazon' as source, SKU FROM amazonlistings WHERE SKU = '$channelskuarray[$i]') UNION (SELECT 'ebay', SKU FROM eba ...

相关文章

更多

最新问答

更多
  • 获取MVC 4使用的DisplayMode后缀(Get the DisplayMode Suffix being used by MVC 4)
  • 如何通过引用返回对象?(How is returning an object by reference possible?)
  • 矩阵如何存储在内存中?(How are matrices stored in memory?)
  • 每个请求的Java新会话?(Java New Session For Each Request?)
  • css:浮动div中重叠的标题h1(css: overlapping headlines h1 in floated divs)
  • 无论图像如何,Caffe预测同一类(Caffe predicts same class regardless of image)
  • xcode语法颜色编码解释?(xcode syntax color coding explained?)
  • 在Access 2010 Runtime中使用Office 2000校对工具(Use Office 2000 proofing tools in Access 2010 Runtime)
  • 从单独的Web主机将图像传输到服务器上(Getting images onto server from separate web host)
  • 从旧版本复制文件并保留它们(旧/新版本)(Copy a file from old revision and keep both of them (old / new revision))
  • 西安哪有PLC可控制编程的培训
  • 在Entity Framework中选择基类(Select base class in Entity Framework)
  • 在Android中出现错误“数据集和渲染器应该不为null,并且应该具有相同数量的系列”(Error “Dataset and renderer should be not null and should have the same number of series” in Android)
  • 电脑二级VF有什么用
  • Datamapper Ruby如何添加Hook方法(Datamapper Ruby How to add Hook Method)
  • 金华英语角.
  • 手机软件如何制作
  • 用于Android webview中图像保存的上下文菜单(Context Menu for Image Saving in an Android webview)
  • 注意:未定义的偏移量:PHP(Notice: Undefined offset: PHP)
  • 如何读R中的大数据集[复制](How to read large dataset in R [duplicate])
  • Unity 5 Heighmap与地形宽度/地形长度的分辨率关系?(Unity 5 Heighmap Resolution relationship to terrain width / terrain length?)
  • 如何通知PipedOutputStream线程写入最后一个字节的PipedInputStream线程?(How to notify PipedInputStream thread that PipedOutputStream thread has written last byte?)
  • python的访问器方法有哪些
  • DeviceNetworkInformation:哪个是哪个?(DeviceNetworkInformation: Which is which?)
  • 在Ruby中对组合进行排序(Sorting a combination in Ruby)
  • 网站开发的流程?
  • 使用Zend Framework 2中的JOIN sql检索数据(Retrieve data using JOIN sql in Zend Framework 2)
  • 条带格式类型格式模式编号无法正常工作(Stripes format type format pattern number not working properly)
  • 透明度错误IE11(Transparency bug IE11)
  • linux的基本操作命令。。。