2012-04-24 2 views
0

C++에서 쉼표 연산자 오버로드에 대한 많은 게시물 (질문)이 있습니다. 대부분의 답변 조언은 쉼표 연산자 오버로드를 사용하지 마십시오. Matlab 언어와 매우 유사한 구문으로 C++ 라이브러리를 작성하고 싶습니다. 기본 개체는 Matrix MX입니다.C++ 쉼표 연산자 오버로드 및 참조 벡터

MX a = b(i);// get b elements at indices i 
b(i,j)= a; // set elements of b at indices i,j. 

내가 저장 프록시 클래스를 사용하여 위의 기록으로 세터 &에게 게터 작업을 수행하는 방법에 대한 아이디어가 : 내가 좋아하는 표현을 쓸 수있는 라이브러리의 최종 사용자를 만들 수 있도록하려면 MX 객체에 대한 포인터이며 인덱스 i, j 객체도 저장합니다. 예를 들어, b (i, j)는 프록시 객체 ProxMX (b, i, j)를 생성합니다. 그런 다음 우리는 ProxMX를 MX에 할당하고 visversa (operator =를 사용)를 지정하여 &에 b 요소를 설정하는 작업을 정의합니다. A, B, C는 입력 argments (MX 오브젝트) 및 X, Y, Z이다

(x,y,z)= ff(a,b,c) 

출력 argments 같습니다

내가 작동하도록 도움을 필요로하는 것처럼 호출한다. 나는이 테스트 코드를 작성하기 시작

ff((a,b,c), (x,y,z)) 

: 위의 syntaxe이 가능하지 않은 경우 는 내가 같은 syntaxe에 대해 생각할 수 : VS2010 Express를 사용하여 오류없이

#include "stdafx.h" 
#include <iostream> 
#include <fstream> 
#include <vector> 
using namespace std; 




class MX {// Matrix 

public: 
    MX(double va) { 
     elem=va;// only one double for the moment to test the syntaxe 
    } 
    MX &operator()(MX idx){ // get & set MX(i) 
     return *this;// 
    }; 
    MX &operator()(MX idx1,MX idx2) { // get set MX(i,j) 
     return *this; 
    } ; 
    friend ostream &operator<<(ostream &stream, MX a); 

    double elem; 

}; 

ostream &operator<<(ostream &stream, MX a) 
{ 
    stream << a.elem ; 

    return stream; 
} 

typedef vector<const MX > MXR; 
class ArgList { // Proxy 
public: 
    //ArgList(const MX& a){ 
    // data.push_back(a); 
    //} 
    ArgList() {}; 

    ArgList& operator , (const MX &a){ 
     data.push_back(a); 
     return *this; 
    } 
    ArgList& operator =(ArgList& ins){ 
     for (int i=0 ;i <ins.data.size();i++) 
      (this->data[i]).elem=ins.data[i].elem; 
     return *this; 
    }; 
    MXR data; 
}; 


ArgList operator , (const MX& a, const MX& b){ 
    ArgList out;  
    out.data.push_back(a); 
    out.data.push_back(b); 
    return out; 
    } 

ArgList ff(ArgList argins) 
{ 

    int n = argins.data.size(); 
    MX a= argins.data[0]; 
    MX b= argins.data[1]; 
    MX x(a.elem+1.0); 
    MX y(b.elem+10.0); 
    MX z(a.elem+b.elem); 
    return (x, y , z); 

} 
void gg(ArgList argins, ArgList &argout) 
{ 

    int n = argins.data.size(); 
    MX a= argins.data[0]; 
    MX b= argins.data[1]; 
    MX x(a.elem+1.0); 
    MX y(b.elem+10.0); 
    MX z(a.elem+b.elem); 
    argout = (x, y , z); 

} 
int _tmain(int argc, _TCHAR* argv[]) 
{ 
    MX a(1.0);MX b(2.0);MX c(3.0); 
    MX aa = a(MX(3.0)); 
    aa(MX(2.0),MX(3.0))=MX(5.0); 
    cout << "a=" << a << ",b=" << b << ",c=" << c << endl; 
    MX x(0.0);MX y(0.0);MX z(0.0); 
    cout << "x=" << x << ",y=" << y << ",z=" << z << endl; 
    (x,y,z)= ff((a , b, c)); 
    cout << "x=" << x << ",y=" << y << ",z=" << z << endl; 
    gg((a,b,c) , (x,y,z)); 
    cout << "x=" << x << ",y=" << y << ",z=" << z << endl; 
    return 0; 
} 

이 코드는 & 실행을 컴파일 . 그러나 예상대로 벡터의 객체 복사본을 만드는 대신 ArgList에 변수에 대한 참조를 저장해야하기 때문에 예상 한 결과를 얻지 못합니다. 나는 우리가 std :: vector를 객체에 대한 참조의 컨테이너로 사용할 수 없다는 것을 안다.

논문을 쓰기 가능하게 만들고 C++ 코드로 작업하려면 도움이 필요합니다. 감사합니다. .

+2

실제 문제는 무엇인지 자세히 설명해 주실 수 있습니까? 예상대로 행동하지 않습니까? 'std :: vector'가 아닌 다른 컨테이너가 필요합니까? 다른 것? –

+0

(x, y, z) = ff ((a, b, c))와 같은 표현식을 사용하여 C++에서 함수를 호출하는 데 도움이 필요합니다. 첫 번째 테스트 코드는 객체에 대한 참조를 받아들이는 컨테이너가 올바른 방향이라고 생각하게한다. 하지만 난 쉬지 않아. – Yazou

+2

[Armadillo] (http://arma.sourceforge.net/) 및 [Blitz ++] (http : //)와 같은 MATLAB과 유사한 구문을 제공하는 것을 목표로하는 C++ 용의 기존 오픈 소스 선형 대수 라이브러리가 많이 있습니다. www.oonumerics.org/blitz/). 당신은 그들의 근원을 볼 수 있습니다. – James

답변

2
내가 당신에게 해결책을 (코드가 테스트도)의 윤곽을 C++ (11)를 사용하고

, 그러나 이것은 C++ 03 (사용 예 Boost.Tuple)에서 행할 :

// Base case 
template<typename Lhs, typename Rhs> 
std::tuple<Lhs&, Rhs&> 
operator,(Lhs& lhs, Rhs& rhs) 
{ 
    return std::tie(lhs, rhs); 
} 

// General case when we already have a tuple 
template<typename... Lhs, typename Rhs> 
std::tuple<Lhs..., Rhs&> 
operator,(std::tuple<Lhs...>&& lhs, Rhs& rhs) 
{ 
    return std::tuple_cat(lhs, std::tie(rhs)); 
} 

(이 조작을 가정하면 namespace ns에 상주하는)과 같은 사용법 같습니다

// Declaration: note how ff must return a tuple 
std::tuple<X, Y, Z> ff(A, B, C); 

A a = /* ... */; 
B b = /* ... */; 
C c = /* ... */; 
X x; Y y; Z z; 

using ns::operator,; 
// brackets on the left-hand side are required 
(x, y, z) = ff(a, b, c); 
여기

있는 첨부주의 :

  • 을 보셨으므로 operator,을 가져 오는 데 사용 선언이 필요합니다. X, Y, Z 유형이 operator, (ADL 사용 가능)의 동일한 범위에있는 경우에도 std::tuple은 포함되지 않습니다. template<typename... T> struct tuple: std::tuple<T...> { using std::tuple<T...>::tuple; }; (C++ 03에서는 편리하지는 않지만) 적절한 네임 스페이스에 고유 한 튜플을 사용하여 ADL을 신속하고 더러운 방식으로 처리 할 수 ​​있습니다. 그러나 :

  • 과부하가 걸린 운영자는 항상 하나 이상의 사용자 정의 유형에서 작동해야합니다. 따라서 XY 유형이 모두 int 또는 double과 같은 유형 인 경우 기본값은 operator,입니다.이와 같은 일에 대한 일반적인 해결책은 클라이언트가 대신 (ref(x), ref(y), z) = ff(a, b, c);과 같은 것을 요구하는 것입니다. 여기서 ref은 적절한 네임 스페이스의 유형을 반환합니다 (다시 ADL 용도로). 아마도 이러한 타입은 튜플에 대해 똑같은 더러운 해킹을 사용하여 std::reference_wrapper (또는 Boost 버전, C++ 03)으로 구현 될 수 있습니다. (당신은 operator,의 추가 오버로드를 필요 했어.)

모두 모두, 즉 많은 작업 (추한 해결 방법으로) 때

/* declaration of ff and variable definitions the same as before */ 
std::tie(x, y, z) = ff(a, b, c); 

혹은

/* this skips unnecessary default constructions of x, y, z */ 
auto tuple = ff(a, b, c); 
using std::get; 
auto& x = get<0>(tuple); 
auto& y = get<1>(tuple); 
auto& z = get<2>(tuple); 
같은

은 (Boost.Tuple이있는 C++ 03에서도) 즉시 사용할 수 있습니다. 이 문제에 대한 나의 조언은 (의도하지 않은 채로) : 간단하고 어리 석다! 그리고 그것을 사용하십시오. 컴파일러가 지원하지 않는 경우

에서, Boost.Tuple 라이브러리와 매우 유사하다
std::tuple<some_type, another_type, yet_another_type> ff(...); 

some_type x; 
another_type y; 
yet_another_type z; 

std::tie(x,y,z) = ff(a,b,c); 

하지만, 가변 인자 템플릿의 지원없이 더 제한 될 수 있습니다 :

+0

고마워. Visual Studio 2010을 사용하고 있기 때문에 지금이 코드를 시도 할 수 없습니다. C++ 11은 가까운 장래에 가능할 수 있기 때문에 현재로서는 실제 옵션이 아닙니다 .BTW, ns :: 연산자는 무엇입니까? – Yazou

+0

C++에서 (x, y) = ff (a, b)를 쓸 수 없다면 ff (a, b, IO_DUMMY_SEP, x, y)를 쓰는 것이 좋을 것입니다.) 자동 튜플보다 우아하고 솔루션을 얻으십시오. 동의하니? – Yazou

+0

@ Yazou 다시 말하지만 C++ 03 ('std :: tuple'은 Boost.Tuple의 작업을 기반으로합니다.)에서 구현할 수 있습니다. (예 : 가변성이 없기 때문에 템플릿). 'ns :: operator '는'ns'라는 가상의 네임 스페이스에서'연산자'를 지정합니다; 왜냐하면 전역 네임 스페이스에서 연산자를 오버로드하지 않기 때문에 모든 연산자를 포기해야하기 때문입니다. 마지막으로 내가 추천하는 * first * 옵션은 사용자가'X x; Y y; tie (x, y) = ff (a, b);'; 두 번째 변형은 특수한 용도입니다 (기본 구성이 불가능하거나 너무 비싸다). –

2

C++ 11에서는이 사용 튜플을 수행 할 수 있습니다 .

(x,y,z) = ff(a,b,c);과 같은 구문을 지원하고 싶다면 Matlab에서 현명한 것처럼 보일지라도 C++ 프로그래머에게 다소 혼란 스러울 수 있습니다. ArgList과 비슷한 별도의 유형이 필요합니다 (예 : RefList). 값 대신 포인터가 포함되어 있으며 결과에 대한 참조가 아닌 const에서이 포인터를 초기화하고 할당 연산자는 ArgList (또는 다른 컬렉션 of values) 포인터를 통해 각 요소를 지정합니다.

이러한 연산자 오버로드가 어떻게 작동하는지 알기 위해서 Boost.Assignment을보고 싶을 수도 있습니다. 그것은 번거롭다. 특히 기본 제공 유형에서만 작동하는 연산자를 오버로드 할 수 없으므로 이러한 접근 방식의 유용성이 제한됩니다. 개인적으로, 나는 C++ 11이 옵션 인 경우에 대신 가변성 템플릿을 사용할 것입니다.

+0

고마워. 나는 Boost.Assignement를 이미 고려했다. 그러나 나는 C++ 11에서 std :: tuple에 대해 몰랐다. 내가 원하는 것은 내 lib의 최종 사용자를 위해 std :: anything (x, y, z, w, t)을 사용하는 것을 피하는 것이다. 내 lib에 프록시 클래스를 작성하여 최종 사용자를위한 구문을 매우 간단하고 매우 깨끗하게 유지할 수 있습니다. 내 최종 사용자는 C++ 프로그래머가 아니라 Matlab 프로그래머입니다. std :: tuple이 작동하면 튜플을 구성하는 콤마 연산자를 제공해야합니다. 장면은 최종 표현식을 만듭니다. (x, y, z, t, w) = ff (a, b, c, d, f, g). – Yazou

+0

@ Yazou : 당신이 어떻게 습득 할 수 있는지에 대한 몇 가지 지침을 추가했습니다. C++에 익숙한 사람에게는 코드가 다소 이상하게 보일 것임을 알아 두십시오. –

+0

@Mile : 다시 한번 감사드립니다. C++ 11이 옵션이 아닌 경우. MX 객체에 대한 참조를 저장하기 위해 첫 attemp 코드 (ArgList Proxy)에서 사용할 수있는 candidat 컨테이너는 무엇입니까? – Yazou

0

의견을 보내 주신 모든 분께 & 의견을 보내 주셔서 감사합니다. 여기 은 2 개의 프록시를 사용하는 작동 예제입니다. ArgList는 MX 객체에 대한 포인터를 포함하고 ArgCopyList는 MX 객체의 사본을 포함합니다.

matlab 사용자 입장에서 보면 C++ 구문 (x,y,...)=myfunc((a,b,...))은 matlab 표현식 [x,y,...]=myfunc(a,b,...)과 매우 유사합니다. 하지만 내 첫 번째 인상은 반환 된 값을 복사하여 참조로 출력을 전달함으로써 피할 수 있기 때문에 이런 종류의 함수 호출이 효율적이지 않다는 것입니다.

#include "stdafx.h" 
#include <iostream> 
#include <fstream> 
#include <vector> 
using namespace std; 

class MX {// Matrix 

public: 
    MX(double va) { 
     elem=va;// only one double for the moment to test the syntaxe 
    } 
    MX & operator = (const MX &src) 
    { elem = src.elem; 
     return *this; 
    } 
    friend ostream &operator<<(ostream &stream, MX &a); 

    double elem; 

}; 

ostream &operator<<(ostream &stream, MX &a) 
{ 
    stream << a.elem ; 

    return stream; 
} 

typedef vector<MX *> MXR; // save pointers only 

class ArgCopyList { // copy the objects to a list 
public : 
    vector<const MX> data; 
    ArgCopyList(MX &a) 
    { 
     data.push_back(a); 
    }; 
    ArgCopyList(MX &a, MX &b) 
    { 
     data.push_back(a); 
     data.push_back(b); 
    }; 
    ArgCopyList(MX &a, MX &b, MX &c) 
    { 
     data.push_back(a); 
     data.push_back(b); 
     data.push_back(c); 
    }; 
    // do the same for bigger lists 

}; 

class ArgList { // Proxy 
public: 

    ArgList() {}; 

    ArgList(const ArgList& src) 
    { 
     data.clear(); 
     for (int i=0 ;i <src.data.size();i++) 
      data.push_back(src.data[i]); 
    } 
    ArgList& operator , (MX &a){ 
     data.push_back(&a); 
     return *this; 
    } 

    ArgList &operator= (ArgList &src) 
    { 
     if (this == &src) 
      return *this; 
     data.clear(); 
     int n= src.data.size(); 
     for (int i=0 ;i <n;i++) 
      data.push_back(src.data[i]); 
     return *this; 
    }; 


    ArgList& operator =(ArgCopyList& src){ 
     for (int i=0 ;i <data.size();i++)// TBD : must control the size of src & this->data here 
      data.at(i)->elem = (src.data[i].elem); 
     return *this; 
    }; 
    MXR data; 
}; 


ArgList operator , (MX& a, MX& b){ 
    ArgList out;  
    out.data.push_back(&a); 
    out.data.push_back(&b); 
    return out; 
    } 

// test function 
ArgCopyList ff(ArgList argins) 
{ 

    int n = argins.data.size(); 
    MX a= *(argins.data[0]); 
    MX b= *(argins.data[1]); 
    MX x(a.elem+1.0); 
    MX y(b.elem+10.0); 
    MX z(a.elem+b.elem); 
    return ArgCopyList(x, y , z); 

} 


int _tmain(int argc, _TCHAR* argv[]) 
{ 

    MX a(1.0);MX b(2.0);MX c(3.0); 
    cout << "a=" << a << ",b=" << b << ",c=" << c << endl; 

    MX x(0.0);MX y(0.0);MX z(0.0); 
    cout << "Argouts before calling (x,y,z)= ff((a,b,c)).\nx=" << x << ",y=" << y << ",z=" << z << endl; 

    (x,y,z)= ff((a , b, c)); 

    cout << "Argouts after calling ff.\nx=" << x << ",y=" << y << ",z=" << z << endl; 
    return 0; 
} 

/* output 
a=1,b=2,c=3 
Argouts before calling (x,y,z)= ff((a,b,c)). 
x=0,y=0,z=0 
Argouts after calling ff. 
x=2,y=12,z=3 
*/