可变模板算子<< [英] Variadic template operator<<

查看:122
本文介绍了可变模板算子<<的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想改变我的一些功能 foo()运算符<<()只是为了得到一些半C /半C ++代码看起来更像C ++。不过,发生以下变数步骤:

  template< class ... T> 
inline const size_t foo(const T& ... data){
return sizeof ...(T);
}
struct bar {
template< class ... T>
inline const size_t operator<<(const T& ... data){
return sizeof ...(T);
}
};
int main(int argc,char * argv []){
bar a;
std :: cout<< >>>>>长度< foo(1,2,3)<< std :: endl;
std :: cout<< >>>>>长度< (a <1 <2)<1。 std :: endl;
std :: cout<< >>>>>长度< (a <1 <2 <3)<1。 std :: endl;
std :: cout<< >>>>>长度< (a <1 <2 <3 <4)<1。 std :: endl;
}

从输出:

  $ ./a.out 
>>>长度3
>>>>长度4
>>>> length 32
>>>>长度512

我总结第一个计算是在 a< 1 ,并且随后的值相应地移位。然而,我没有看到我可以重写 foo(),因为提供了一个运算符<<() foo()的用户 > semantics。



如果没有办法将 class T ... 作为参数传递给运算符<<(),该函数自然效率低于 foo(),因为它将被调用多次。是否有任何合理的C ++结构,或坚持 foo()是唯一/最好的选择吗?



上下文



这些 foo()函数是网络通信的发送者/接收者。我认为最好使用< 提供更多的C ++接口和发送者/接收者流, > 运算符 - 除了使用常规函数 foo(...)



在关联性方面,以下是等同的(

code><<
>> 是从左到右的关联):

  a< 1<< 2 
(a << 1)< 2

调用 a< 1 调用您的用户定义的运算符,然后返回 size_t 。这就是为什么下一次调用的类型如下: size_t<< int (这是一个简单的按位移位)。



您需要使用表达式模板。思路如下( 此处的示例 ):

 模板< typename ... args> 
struct stream_op
{
};

template< typename ... A,typename B>
stream_op< A ...,B> operator<<<<(stream_op< A ...> a,B b)
{
// Do stuff
}

因此,发生以下情况( a 为 stream_op< code>):

  a< 1<< 2 
------
|
v
------------------------------------------ -
stream_op< int>运算符<<(stream_op<>,int)< 2
-------------- ---
| |
| + --------------------------- +
vv
------------- - ---
stream_op< int> << int
-------------- ---
| |
| + --------------------------- +
+ ---------------- ------------ + |
v v
-------------- ---
stream_op< int,int> operator<<(stream_op< int>,int)
------------------
|
v
------------------
stream_op< int,int> // < - 预期结果

然后你只需要一个方法转换 stream_op 到int(或任何你想要的)。



关于性能的说明:使用这些表达式模板,是在类型中编码的,因此通常应该像直接调用 foo(...)一样快。


I'm trying to change some of my functions foo() into operator<<(), simply for the sake of getting some "half C/half C++" code to look more like C++. Happens, though, I've got stuck at the following transformation step:

template <class... T>
inline const size_t foo(const T&... data) {
    return sizeof...(T);
}
struct bar {
    template <class... T>
    inline const size_t operator<<(const T&... data) {
        return sizeof...(T);
    }
};
int main(int argc, char *argv[]) {
    bar a;
    std::cout << ">>> length " << foo(1, 2, 3) << std::endl;
    std::cout << ">>> length " << (a << 1 << 2) << std::endl;
    std::cout << ">>> length " << (a << 1 << 2 << 3) << std::endl;
    std::cout << ">>> length " << (a << 1 << 2 << 3 << 4) << std::endl;
}

From the output:

$ ./a.out 
>>> length 3
>>> length 4
>>> length 32
>>> length 512

I conclude the first computation is performed upon a << 1, and the subsequent values are shifted accordingly. Yet, I'm failing to see how I could rewrite foo(), as to provide a operator<<() interface to users of struct bar -- of course, without changing foo() semantics.

In case there's no way to pass class T... as parameter to operator<<(), the function would be naturally less efficient than foo(), as it would be called many times. Is there any reasonable C++ construct for this, or sticking to foo() is the only/best option here?

Context:

These foo() functions are senders/receivers to network communication. I thought that would be better to provide a more "C++" interface, with a sender/receiver stream, writable/readable using << and >> operators -- other than using regular functions foo(...).

解决方案

The language is doing what you are asking it to do.

With associativity, the following are equivalent (<< and >> are left-to-right associative):

a << 1 << 2
(a << 1) << 2

The call a << 1 calls your user-defined operator, which in turn returns a size_t. That's why the types for next call are the following: size_t << int (which is a simple bitwise shift).

You need to use expression templates. The idea is the following (live example here):

template<typename... args>
struct stream_op
{
};

template<typename... A, typename B>
stream_op<A..., B> operator<<(stream_op<A...> a, B b)
{
    // Do stuff
}

So, the following occur (with a as a stream_op<>):

a << 1 << 2
------
  |
  v
-------------------------------------------
stream_op<int> operator<<(stream_op<>, int) << 2
--------------                                ---
     |                                         |
     |             +---------------------------+
     v             v
--------------    ---
stream_op<int> << int
--------------    ---
       |           |
       |           +---------------------------+
       +----------------------------+          |
                                    v          v
                              --------------  ---
stream_op<int,int> operator<<(stream_op<int>, int)
------------------
        |
        v
------------------
stream_op<int,int> // <- Expected result

Then you just have to put a method to convert stream_op to int (or to whatever you want).

A note on performances: with these expression templates, a part of the data is encoded in the type, so normally it should be as fast as a direct call to foo(...).

这篇关于可变模板算子&lt;&lt;的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆