问题
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(...)
.
回答1:
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(...)
.
来源:https://stackoverflow.com/questions/17868718/variadic-template-operator