2013-03-26 3 views
23

C++ 11 덕분에 이제는 매크로, 사용자 정의 리터럴, 람다 등을 결합하여 '구문 설탕'에 가장 가까이있는 것을 만들 수 있습니다. 예를 들어새 삽입 연산자 정의

if (A contains B) 

물론 쉽습니다.

cout <<("hello"_s contains "ello"_s)<<endl; 

식은 인수로서 좌측과 우측을 얻어 맞춤 구조체이다 포함 BOOL로 변환한다. 구조체는 operator +를 오버로드하여 사용자 정의 문자열 리터럴을 먼저 가져 와서 자체를 반환 한 다음 구조체 자체에 대한 연산자 +를 오버로드합니다.

struct contains_struct { 
    string lhs; 
    string rhs; 
    void set_lhs(string lhs) { this->lhs = lhs; } 
    void set_rhs(string rhs) { this->rhs = rhs; } 
    operator bool() const { 
     return string::npos != lhs.find(rhs); 
    } 
} contains_obj; 

contains_struct& operator+(const string& lhs, const contains_struct& rhs) { 
    contains_obj.set_lhs(lhs); 
    return contains_obj; 
} 

contains_struct& operator+(const contains_struct& lhs, const string& rhs) { 
    contains_obj.set_rhs(rhs); 
    return contains_obj; 
} 

#define contains +contains_obj+ 

이제 나는 더 가고 싶다고 결정했습니다. 어떤 약

(x in a) perform cube 

그것은 목록의 이해가 아니지만 그것은 꽤 좋은 예입니다. 처음에는 잘 정의 된 연산자 우선 순위에 대해 물어보기 위해 stackoverflow에 가야 겠지만 올바른 생각을 가진 사람이 내 코드를 사용하지 않으므로 괄호 안에 넣는 것이 간단합니다. 대신, 나는 다른 예제를 확장하고 '포함'과 같이 사용자 지정 구조체로 'in'및 'perform'을 포함합니다.

x가 임의의 숫자 인덱스가 될 수 있도록 템플릿을 추가하고 템플릿을 만들 수 있지만 간단히하기 위해 x는 정수로, a는 int 벡터로 남겨 둡니다. 이제까지는 로컬 변수 x를 인수로 사용하지 않고 operator string() 함수에서 로컬 변수를 사용합니다. Overloading assignment operator for type deduction

내가 그것을 반환에 대해 하나의 실용화를 실현 : 일을 단순화하기 위해

, 나는 또 다른 질문에 이렇게

operator string() const { 
    string s = ""; 
    for (int x : lhs.rhs) 
     s += to_string(rhs(x)) + string("\n"); 
    return s; 
} 
같은 문자열

감사 식의 결과를 저장

struct result_struct { 
    vector<int> results; 
    result_struct(vector<int> results) { this->results = results; } 
}; 

... 

    operator result_struct() const { 
     vector<int> tmp; 
     for (int x : lhs.rhs) 
      tmp.push_back(rhs(x)); 
     return result_struct(tmp); 
    } 

... 

result_struct result_2 = (x in a) perform cube; 
    for (int x : result_2.results) 
     cout <<x<<endl; 

: 과제는 다음과 같다 milleniumbug's answer에 617,451,515,

덕분에, 내가 할 수있는 :

struct for_obj 
{ 
    int _lhs; 
    std::vector<int> _rhs; 
    for_obj(int lhs, std::vector<int> rhs) 
     : _lhs(lhs), _rhs(rhs) { } 
}; 

INFIX_OPERATOR(for_obj, in_op, int, std::vector<int>) 
{ 
    return for_obj(lhs(), rhs()); 
} 
#define in + in_op() + 

INFIX_OPERATOR(int, perform_op, for_obj, std::function<int(int)>) 
{ 
    for (int i = 0; i < lhs()._rhs.size(); i++) 
     rhs()(lhs()._rhs[i]); 
    return 0; 
} 
#define perform + perform_op() + 

두 가지주의 사항이 있습니다. 먼저 int를 반환하여 더미 변수에 할당하여 실행할 수 있도록합니다. 나는 항상 전에했던 result_struct 일을 할 수도 있고 std :: function 객체를 반환하여 그 자체로 호출 할 수도 있지만 나 자신을 반복 할 것입니다. 다른주의 사항은 매크로에 너무 많은 const가 있기 때문에 lhs를 수정할 수 없다는 것입니다 (반복자를 지정할 수는 없습니다).

모든 사항은 다음과 같이 예상됩니다.

int x = 0; 
std::vector<int> nums = { 1, 2, 3 }; 
auto cube = [] (int x) 
{ 
    std::cout << x * x * x << std::endl; 
    return x * x * x; 
}; 
int i = (x in nums) perform cube; 

새로운

class PerformObj { 
    int counter; 
public: 
    PerformObj() : counter(0) { } 
    ~PerformObj() { } 
    InObj lhs; 
    std::function<int(int)> rhs; 

    operator int() const { 
     return rhs(lhs.rhs[counter]); 
    } 
} performobj; 

#define perform + performobj + 

PerformObj& operator+(const InObj& lhs, PerformObj& rhs) { 
    rhs.lhs = lhs; 
    return rhs; 
} 

PerformObj& operator+(PerformObj& lhs, const std::function<int(int)>& rhs) { 
    lhs.rhs = rhs; 
    return lhs; 
} 

int main() 
{ 
    std::vector<int> nums = {1,2,3}; 
    int x = 0; 

    auto cube = [] (int n) { 
     return n * n * n; 
    }; 

    std::cout << x in nums perform cube << std::endl; 
} 

explicit operator std::vector<int>() const { 
    std::vector<int> temp; 
    for (int i = 0; i < lhs.rhs.size(); i++) { 
     temp.push_back(rhs(lhs.rhs[i])); 
    } 
    return temp; 
} 

int y = 0; 
std::cout << y in static_cast<std::vector<int>>(x in nums perform cube) perform std::function<int(int)>([] (int i) -> int { 
     return i; 
}) << std::endl; 

내가 그것을 그렇게 그 대신 중위 연산자, 후위 운영자가 확인해야 버전, "String literal"s.contains "Other string literal"s 같은, 또는 기능 스타일을, "String literal"s.contains("Other string literal"s) ?

확장 성을 높이기 위해 코드를 개선하는 방법은 무엇입니까? 지금 당장은 매우 오염되었습니다. 이 작업을 수행하는 더/더 일반화 된/덜 clunky 한 방법이 있습니까? 예를 들어, 표현식을 일반화하여 정의 문이 필요 없거나 코드를 재사용 할 수 있습니다.

+14

이 난처에 대한 좋은 기술이지만, definitly해야 그렇지 않으면 피하십시오. C++을 아는 사람이 코드를 읽을 수 없도록 만듭니다. –

+0

표현 템플릿을 재발 명하는 것 같습니다 ... 용어를 찾아 보면 충분히 찾을 수 있습니다. 그러나 언어에 새로운 중절 삽입 연산자를 도입하는 것은 나쁜 생각입니다. 함수 호출 표기법을 고수하거나 인기를 잃습니다. – Potatoswatter

+4

흥미롭고 깔끔하기 때문에 나는 이것을 upvoting하고있다. 그러나 나는 실제 코드에서 실제 사용을 위해 그것을지지하지 않는다. –

답변

11

최신 수정 사항에 모든 질문이 있다고 가정 할 때 여기에서 묻는 질문을보기가 어렵습니다. 대신 중위 연산자 것을, "문자열 리터럴"s.contains "다른 문자열 리터럴"의 같은 접미사 사업자, 거기 있도록

나는 그것을 만들 경우, 또는 그것을 기능 스타일, "문자열 리터럴"의 작업을 수행 .contains ("다른 문자열 리터럴"s)?

예. "String literal"s.contains("Other string literal"s)은 C++ 프로그래머에게 간결하고 명확하며 다른 언어 (Java 및 Python 문자열에 메서드가 있음)의 프로그래머에게 명확하고 템플릿 마법이나 매크로 매직이 사용되지 않는 가장 좋은 방법입니다.

확장 성을 높이기 위해 코드를 개선하려면 어떻게해야합니까? 지금은 바로 이므로 매우 오염되었습니다. 더 나은 /보다 일반화 된/덜 이것을 할 clunky 방법 있는가? 예를 들어, 표현식을 일반화하기 위해 은 정의 문이나 코드 재사용이 필요하지 않습니다.

예! 하지만 어느 정도 (여기에 불필요한 저기 consts 제거) :

#define INFIX_OPERATOR(rettype, name, LT, RT) \ 
struct name\ 
{\ 
private:\ 
    LT* left;\ 
    RT* right;\ 
\ 
protected:\ 
    LT& lhs() const { return *left; }\ 
    RT& rhs() const { return *right; }\ 
\ 
public: \ 
    friend name operator+(LT& lhs, name && op)\ 
    {\ 
     op.left = &lhs;\ 
     return op;\ 
    }\ 
\ 
    friend name operator+(name && op, RT& rhs)\ 
    {\ 
     op.right = &rhs;\ 
     return op;\ 
    }\ 
\ 
    name() : left(nullptr), right(nullptr) {}\ 
\ 
    operator rettype() const;\ 
};\ 
\ 
inline name :: operator rettype() const 

을 그리고 당신은이처럼 중위 연산자를 만들 수 있습니다 : #을 방지 할 수있는 방법이 없다는 것을

#include <iostream> 
#include <string> 

INFIX_OPERATOR(bool, contains_op, const std::string, const std::string) 
{ 
    return std::string::npos != lhs().find(rhs()); 
} 
#define contains + contains_op() + 

int main() 
{ 
    std::string a = "hello"; 
    std::string b = "hell"; 
    if(a contains b) 
     std::cout << "YES"; 
} 

주 define 매크로는 다른 매크로 지시문을 사용하여 매크로 지시문을 만들 수 없기 때문에 지시문을 포함합니다.

있는 (이 같은 현실 세계의 코드를 사용하여 모든 합리성을 무시하고. 내 말은 당신이 금지, 내가 그것을 사용하고 무엇을 그것의 무엇을 얻을 수있는 경우이의 실제 혜택은 무엇인가 레크리에이션 용도?) C++을 배우는 대신 내 친구가 Bash 또는 Perl 환경에서 쉽게 추상화 된 인터페이스를 원하지만 이 gcc 외부에서 컴파일/링크하지 않고 공동 작업을하고 싶어한다고 가정 해보십시오. 그 방법, 그는 '스크립트'또는 '코드'C++로 작성하고 컴파일 할 수 있으며 내 프로그램/라이브러리/인터페이스와 연결합니다.

다른 언어를 사용하여 언어를 만들려고하는 것 같습니다.를 위해 준비하십시오

  • 언어 테스트를 시도하는 시간과 시간.
  • 당황스럽게도 진단 메시지가 좋지 않습니다. 이것을 컴파일하려고 시도하십시오 : std::vector<void> myarr; 그런 다음 매크로로 포장하십시오. 그런 다음 다른 템플릿으로 포장하십시오. 그리고 다른 매크로에서 ... 아이디어를 얻습니다.
  • 처리 된 코드를 보여주는 디버깅 도구.
  • 귀하의 언어가 완벽하게 통합 되더라도, 당신은 여전히 ​​많은 수의 규칙과 복잡한 유형의 시스템으로 C++을 돌보고 있습니다. After all, all abstractions are leaky.

친구가 Perl로 프로그램하고 싶다면 그냥 해보라고하십시오. 이 언어는 C 언어와 쉽게 연결할 수 있습니다.

다른 언어로는 사용자가하려는 것을 명확하게 표현할 수 없기 때문에 언어를 만들려고 시도하는 경우 파서 생성기 (Flex/Bison, ANTLR) 및 LLVM을 사용하면 쉽게 사용할 수 있습니다.

구문 분석기를 만들면 잔인합니다. D 언어 믹스 인을 살펴보십시오. 그들은 컴파일 타임에 생성 된 문자열을 받아 들인 다음 직접 삽입 한 것처럼 컴파일합니다.

import std.stdio; 
int main() 
{ 
    write("Hello world"); 
    return 0; 
} 

이 단순한 예이다 : 여기에

...

import std.stdio; 
int main() 
{ 
    mixin(`write("Hello world");`); //`contents` is a raw string literal 
    return 0;      //so is r"contents" 
} 

는 동일하다. 당신은 문자열 구문 분석 함수 수 :

mixin(user1508519s_language(r"(x in a) perform cube")); 

1를 - 여기 보이는 방법이다 (GCC 4.7.2) :

In file included from c:\__moje\prog\mingw\bin\../lib/gcc/mingw32/4.7.2/include/ 
c++/bits/stl_construct.h:63:0, 
       from c:\__moje\prog\mingw\bin\../lib/gcc/mingw32/4.7.2/include/ 
c++/vector:63, 
       from #templateerrors2.cpp:1: 
c:\__moje\prog\mingw\bin\../lib/gcc/mingw32/4.7.2/include/c++/ext/alloc_traits.h 
: In instantiation of 'struct __gnu_cxx::__alloc_traits<std::allocator<void> >': 

c:\__moje\prog\mingw\bin\../lib/gcc/mingw32/4.7.2/include/c++/bits/stl_vector.h: 
76:28: required from 'struct std::_Vector_base<void, std::allocator<void> >' 
c:\__moje\prog\mingw\bin\../lib/gcc/mingw32/4.7.2/include/c++/bits/stl_vector.h: 
208:11: required from 'class std::vector<void>' 
#templateerrors2.cpp:5:19: required from here 
c:\__moje\prog\mingw\bin\../lib/gcc/mingw32/4.7.2/include/c++/ext/alloc_traits.h 
:189:53: error: no type named 'reference' in 'class std::allocator<void>' 
c:\__moje\prog\mingw\bin\../lib/gcc/mingw32/4.7.2/include/c++/ext/alloc_traits.h 
:190:53: error: no type named 'const_reference' in 'class std::allocator<void>' 
In file included from c:\__moje\prog\mingw\bin\../lib/gcc/mingw32/4.7.2/include/ 
c++/vector:65:0, 
       from #templateerrors2.cpp:1: 
c:\__moje\prog\mingw\bin\../lib/gcc/mingw32/4.7.2/include/c++/bits/stl_vector.h: 
In instantiation of 'class std::vector<void>': 
#templateerrors2.cpp:5:19: required from here 
c:\__moje\prog\mingw\bin\../lib/gcc/mingw32/4.7.2/include/c++/bits/stl_vector.h: 
292:7: error: forming reference to void 
c:\__moje\prog\mingw\bin\../lib/gcc/mingw32/4.7.2/include/c++/bits/stl_vector.h: 
467:7: error: forming reference to void 
c:\__moje\prog\mingw\bin\../lib/gcc/mingw32/4.7.2/include/c++/bits/stl_vector.h: 
684:7: error: invalid parameter type 'std::vector<void>::value_type {aka void}' 
c:\__moje\prog\mingw\bin\../lib/gcc/mingw32/4.7.2/include/c++/bits/stl_vector.h: 
684:7: error: in declaration 'void std::vector<_Tp, _Alloc>::resize(std::vector< 
_Tp, _Alloc>::size_type, std::vector<_Tp, _Alloc>::value_type)' 
c:\__moje\prog\mingw\bin\../lib/gcc/mingw32/4.7.2/include/c++/bits/stl_vector.h: 
881:7: error: forming reference to void 
In file included from c:\__moje\prog\mingw\bin\../lib/gcc/mingw32/4.7.2/include/ 
c++/vector:70:0, 
       from #templateerrors2.cpp:1: 
c:\__moje\prog\mingw\bin\../lib/gcc/mingw32/4.7.2/include/c++/bits/vector.tcc:10 
8:5: error: forming reference to void 
In file included from c:\__moje\prog\mingw\bin\../lib/gcc/mingw32/4.7.2/include/ 
c++/vector:65:0, 
       from #templateerrors2.cpp:1: 
c:\__moje\prog\mingw\bin\../lib/gcc/mingw32/4.7.2/include/c++/bits/stl_vector.h: 
1003:7: error: forming reference to void 
c:\__moje\prog\mingw\bin\../lib/gcc/mingw32/4.7.2/include/c++/bits/stl_vector.h: 
1179:7: error: forming reference to void 
In file included from c:\__moje\prog\mingw\bin\../lib/gcc/mingw32/4.7.2/include/ 
c++/vector:70:0, 
       from #templateerrors2.cpp:1: 
c:\__moje\prog\mingw\bin\../lib/gcc/mingw32/4.7.2/include/c++/bits/vector.tcc:21 
6:5: error: forming reference to void 
c:\__moje\prog\mingw\bin\../lib/gcc/mingw32/4.7.2/include/c++/bits/vector.tcc:43 
9:5: error: forming reference to void 
c:\__moje\prog\mingw\bin\../lib/gcc/mingw32/4.7.2/include/c++/bits/vector.tcc:31 
6:5: error: forming reference to void 
In file included from c:\__moje\prog\mingw\bin\../lib/gcc/mingw32/4.7.2/include/ 
c++/vector:65:0, 
       from #templateerrors2.cpp:1: 
c:\__moje\prog\mingw\bin\../lib/gcc/mingw32/4.7.2/include/c++/bits/stl_vector.h: 
In instantiation of 'std::_Vector_base<_Tp, _Alloc>::~_Vector_base() [with _Tp 
= void; _Alloc = std::allocator<void>]': 
c:\__moje\prog\mingw\bin\../lib/gcc/mingw32/4.7.2/include/c++/bits/stl_vector.h: 
247:15: required from 'std::vector<_Tp, _Alloc>::vector() [with _Tp = void; _A 
lloc = std::allocator<void>]' 
#templateerrors2.cpp:5:19: required from here 
c:\__moje\prog\mingw\bin\../lib/gcc/mingw32/4.7.2/include/c++/bits/stl_vector.h: 
161:9: error: invalid use of 'void' 
c:\__moje\prog\mingw\bin\../lib/gcc/mingw32/4.7.2/include/c++/bits/stl_vector.h: 
In instantiation of 'void std::_Vector_base<_Tp, _Alloc>::_M_deallocate(std::_V 
ector_base<_Tp, _Alloc>::pointer, std::size_t) [with _Tp = void; _Alloc = std::a 
llocator<void>; std::_Vector_base<_Tp, _Alloc>::pointer = void*; std::size_t = u 
nsigned int]': 
c:\__moje\prog\mingw\bin\../lib/gcc/mingw32/4.7.2/include/c++/bits/stl_vector.h: 
161:9: required from 'std::_Vector_base<_Tp, _Alloc>::~_Vector_base() [with _T 
p = void; _Alloc = std::allocator<void>]' 
c:\__moje\prog\mingw\bin\../lib/gcc/mingw32/4.7.2/include/c++/bits/stl_vector.h: 
247:15: required from 'std::vector<_Tp, _Alloc>::vector() [with _Tp = void; _A 
lloc = std::allocator<void>]' 
#templateerrors2.cpp:5:19: required from here 
c:\__moje\prog\mingw\bin\../lib/gcc/mingw32/4.7.2/include/c++/bits/stl_vector.h: 
175:4: error: 'struct std::_Vector_base<void, std::allocator<void> >::_Vector_im 
pl' has no member named 'deallocate' 
In file included from c:\__moje\prog\mingw\bin\../lib/gcc/mingw32/4.7.2/include/ 
c++/bits/stl_algobase.h:66:0, 
       from c:\__moje\prog\mingw\bin\../lib/gcc/mingw32/4.7.2/include/ 
c++/vector:61, 
       from #templateerrors2.cpp:1: 
c:\__moje\prog\mingw\bin\../lib/gcc/mingw32/4.7.2/include/c++/bits/stl_iterator_ 
base_types.h: In instantiation of 'struct std::iterator_traits<void*>': 
c:\__moje\prog\mingw\bin\../lib/gcc/mingw32/4.7.2/include/c++/bits/stl_construct 
.h:127:24: required from 'void std::_Destroy(_ForwardIterator, _ForwardIterato 
r) [with _ForwardIterator = void*]' 
c:\__moje\prog\mingw\bin\../lib/gcc/mingw32/4.7.2/include/c++/bits/stl_construct 
.h:155:7: required from 'void std::_Destroy(_ForwardIterator, _ForwardIterator 
, std::allocator<_T2>&) [with _ForwardIterator = void*; _Tp = void]' 
c:\__moje\prog\mingw\bin\../lib/gcc/mingw32/4.7.2/include/c++/bits/stl_vector.h: 
403:9: required from 'std::vector<_Tp, _Alloc>::~vector() [with _Tp = void; _A 
lloc = std::allocator<void>]' 
#templateerrors2.cpp:5:19: required from here 
c:\__moje\prog\mingw\bin\../lib/gcc/mingw32/4.7.2/include/c++/bits/stl_iterator_ 
base_types.h:182:43: error: forming reference to void