쉼표 연산자를 언제 오버로드해야합니까?
나는 C ++에서 쉼표 연산자를 오버로딩하는 것에 대한 질문을 자주 봅니다 (주로 오버로딩 자체와 관련이 없지만 시퀀스 포인트 개념과 같은 것).
언제 쉼표를 오버로드 해야 합니까? 실제 사용의 몇 가지 예는 무엇입니까?
나는 내가 본 적이 있거나 같은 것을 필요로했던 내 머릿속에서 어떤 예도 생각할 수 없다.
foo, bar;
실제 코드에서는 이것이 언제 실제로 사용되는지 궁금합니다.
강조를 약간 변경해 보겠습니다.
언제 쉼표 를 오버로드 해야 합니까?
답 : 절대로.
예외 : 템플릿 메타 프로그래밍을 수행하는 경우 operator,
연산자 우선 순위 목록 맨 아래에 특수한 위치가 있으므로 SFINAE 가드 등을 구성하는 데 유용 할 수 있습니다.
내가 본 두 가지 실용적인 용도 operator,
는 모두 Boost입니다 .
- Boost.Assign
- Boost.Phoenix – Phoenix lambda가 여러 문장을 지원할 수 있다는 점에서 기본입니다.
여러 인덱스가있는 맵을 인덱싱하기 위해 쉼표 연산자를 사용했습니다.
enum Place {new_york, washington, ...};
pair<Place, Place> operator , (Place p1, Place p2)
{
return make_pair(p1, p2);
}
map< pair<Place, Place>, double> distance;
distance[new_york, washington] = 100;
Boost.Assign은이를 사용하여 다음과 같은 작업을 수행 할 수 있습니다.
vector<int> v;
v += 1,2,3,4,5,6,7,8,9;
그리고 나는 그것이 기발한 언어 해킹에 사용되는 것을 보았고, 몇 가지를 찾을 수 있는지 볼 것입니다.
아하, 나는 그 기발한 용도 중 하나 인 여러 표현 수집을 기억 합니다 . (경고, 어둠의 마법.)
쉼표는 유형의 매개 변수를 취할 수 있다는 점에서 흥미로운 특성을 가지고 있습니다 void
. 이 경우 내장 된 쉼표 연산자가 사용됩니다.
이것은 표현식에 void 유형이 있는지 확인하려는 경우 편리합니다.
namespace detail_
{
template <typename T>
struct tag
{
static T get();
};
template <typename T, typename U>
tag<char(&)[2]> operator,(T, tag<U>);
template <typename T, typename U>
tag<U> operator,(tag<T>, tag<U>);
}
#define HAS_VOID_TYPE(expr) \
(sizeof((::detail_::tag<int>(), \
(expr), \
::detail_::tag<char>).get()) == 1)
나는 독자가 무슨 일이 일어나고 있는지 연습으로 이해하게했다. operator,
오른쪽에있는 동료를 기억하십시오 .
@GMan의 Boost.Assign 예제 와 유사하게 Blitz ++ 는 쉼표 연산자를 오버로드하여 다차원 배열 작업을위한 편리한 구문 을 제공 합니다. 예를 들면 :
Array<double,2> y(4,4); // A 4x4 array of double
y = 1, 0, 0, 0,
0, 1, 0, 0,
0, 0, 1, 0,
0, 0, 0, 1;
에서 SOCI -는 C ++ 데이터베이스 액세스 도서관 그것은 인터페이스의 인바운드 부분의 구현을 위해 사용된다 :
sql << "select name, salary from persons where id = " << id,
into(name), into(salary);
로부터 근거 자주 묻는 질문 :
Q: Overloaded comma operator is just obfuscation, I don't like it.
Well, consider the following:
"Send the query X to the server Y and put result into variable Z."
Above, the "and" plays a role of the comma. Even if overloading the comma operator is not a very popular practice in C++, some libraries do this, achieving terse and easy to learn syntax. We are pretty sure that in SOCI the comma operator was overloaded with a good effect.
One possibility is the Boost Assign library (though I'm pretty sure some people would consider this abuse rather than a good use).
Boost Spirit probably overloads the comma operator as well (it overloads almost everything else...)
Along the same lines, I was sent a github pull request with comma operator overload. It looked something like following
class Mylogger {
public:
template <typename T>
Mylogger & operator,(const T & val) {
std::cout << val;
return * this;
}
};
#define Log(level,args...) \
do { Mylogger logv; logv,level, ":", ##args; } while (0)
then in my code I can do:
Log(2, "INFO: setting variable \", 1, "\"\n");
Can someone explain why this is a good or bad usage case?
One of the practical usage is for effectively using it with variable arguments in macro. By the way, variable arguments was earlier an extension in GCC and now a part of C++11 standard.
Suppose we have a class X
, which adds object of type A
into it. i.e.
class X {
public: X& operator+= (const A&);
};
What if we want to add 1 or more objects of A
into X buffer;
?
For example,
#define ADD(buffer, ...) buffer += __VA_ARGS__
Above macro, if used as:
ADD(buffer, objA1, objA2, objA3);
then it will expand to:
buffer += objA1, objeA2, objA3;
Hence, this will be a perfect example of using comma operator, as the variable arguments expand with the same.
So to resolve this we overload comma
operator and wrap it around +=
as below
X& X::operator, (const A& a) { // declared inside `class X`
*this += a; // calls `operator+=`
}
I use the comma operator for printing log output. It actually is very similar to ostream::operator<<
but I find the comma operator actually better for the task.
So I have:
template <typename T>
MyLogType::operator,(const T& data) { /* do the same thing as with ostream::operator<<*/ }
It has these nice properties
The comma operator has the lowest priority. So if you want to stream an expression, things do not mess up if you forget the parenthesis. Compare:
myLog << "The mask result is: " << x&y; //operator precedence would mess this one up myLog, "The result is: ", x&y;
you can even mix comparisons operators inside without a problem, e.g.
myLog, "a==b: ", a==b;
The comma operator is visually small. It does not mess up with reading when gluing many things together
myLog, "Coords=", g, ':', s, ':', p;
It aligns with the meaning of the comma operator, i.e. "print this" and then "print that".
Here is an example from OpenCV documentation (http://docs.opencv.org/modules/core/doc/basic_structures.html#mat). The comma operator is used for cv::Mat initialization:
// create a 3x3 double-precision identity matrix
Mat M = (Mat_<double>(3,3) << 1, 0, 0, 0, 1, 0, 0, 0, 1);
참고URL : https://stackoverflow.com/questions/5602112/when-to-overload-the-comma-operator
'program story' 카테고리의 다른 글
jQuery를 사용하여 사용자가 해당 필드를 편집하는 동안 텍스트 필드의 첫 글자를 어떻게 대문자로 표시합니까? (0) | 2020.11.22 |
---|---|
"train_test_split"메소드의 매개 변수 "stratify"(scikit Learn) (0) | 2020.11.22 |
NavigationView의 항목에 사용자 지정 서체를 설정하는 방법은 무엇입니까? (0) | 2020.11.22 |
iOS 용 Google지도 SDK를 사용하려면 '번들 리소스 복사'아래의 대상에 GoogleMaps.bundle이 포함되어야합니다. (0) | 2020.11.22 |
Ajax POST 요청에 대한 Laravel csrf 토큰 불일치 (0) | 2020.11.22 |