2009-06-18 2 views
14

내가 할당 된 변수의 유형에 따라 함수의 반환 형식을 변경할 수 있는지 궁금합니다. 다음은 제가 의미하는 바에 대한 간단한 예입니다.템플릿 전문화 기능이없는 함수의 반환 유형 변경. C++

문자열에서 int, bool 또는 float 변수를 구문 분석하는 함수를 만들고 싶습니다. 나는이 기능 템플릿을 예를 들어 ...

Int value = parse("37"); 
Float value = parse("3.14"); 
Bool value = parse("true"); 

나는 변수 유형은 항상 문자열이 될 것입니다 인수 목록에서 결정되어야합니다, 이해합니다. C++로 이것을 수행하는 다른 방법이 있습니까?

답변

31

그리고 그것은 잘 작동해야처럼

는 그럼이 될 수 . 덧붙여, 당신은 단지 클래스를 직접 사용할 수 있습니다. 나는 그것이 일어나는 변환에 대한 프록시은 그냥 사실을 가리 키도록 conversion_proxy로 이름을 변경하는 것을 권장하지만 것을 자체가 나 자신보다 조금 빨리했다 litb에 동의

struct conversion_proxy { 
    string str; 
    conversion_proxy(string const &str):str(str) { } 
    template<typename T> operator T() { 
     return boost::lexical_cast<T>(str); 
    } 
}; 

float a = conversion_proxy("3.1"); 
+0

이것은 약간 잘못 보입니다. 당신은 ctor 연산자를 호출하지 않습니다. 나는 확실하지 않기 때문에 전향하지 않습니다. 명확히하십시오. –

+0

나는 op()를 호출 할 의도가 없었습니다. :) 나는 프록시를 반환 한 함수를 호출했습니다. 두 번째 부분에서는 지금 중간에 중재 함수없이 클래스를 직접 사용하여 제안합니다. –

+0

감사합니다 GMan, 감사합니다. –

0

불행히도, 불가능합니다. C++에서는 반환 값에 따라 함수를 오버로드 할 수 없습니다. ParseInt, ParseFloat 및 ParseBool의 세 가지 함수가 있거나 함수 템플릿을 사용해야합니다.

+0

이 기술적으로 사실 (. 또한 live demo 참조),하지만 당신은 사용자 정의 변환과 거의 같은 일을 달성 할 수 - litb의 훌륭한 대답을 참조하십시오. –

0

void *를 반환 한 다음 필요에 따라 결과를 캐스팅 할 수 있습니다.

그러나 나는 이것에 반대합니다. C++은 강력한 형식의 언어입니다. 이것의 장점은 컴파일러가 동적 유형의 언어보다 먼저 오류를 잡을 수 있다는 것입니다.

+0

실제로 작동하지 않습니다. void *를 반환하는 코드는 void *가 float * 또는 int *로 형 변환 될지 알지 못합니다. 부스트 :: 변종은 잘 정의 된 문제에서 실패 할 것이기 때문에 더 안전합니다.하지만 수정 구슬 문제가 똑같습니다. – MSalters

12

알고 계시지 않겠지 만 궁금한 점이 있으시면 알려 드릴 수는 없지만 실제로 템플릿을 사용하여 해결할 수는 있습니다. 유일한 캐치는 유추에 의존하는 대신 각 호출에서 변환 할 형식을 지정해야한다는 것입니다. 왜냐하면 인수 유형이 항상 같을 것이기 때문입니다.

template<typename T> T parse(const string& str) { /* do stuff for other types */ } 
template<> int parse<int>(const string& str) { /* do stuff for ints */ } 
template<> double parse<double>(const string& str) { /* do stuff for doubles */ } 
template<> bool parse<bool>(const string& str) { /* do stuff for bools */ } 
// etc. 

그리고 당신은 이미 그냥이 답변을 무시 알았다면
int value = parse<int>("37"); 
double value = parse<double>("3.14"); 
bool value = parse<bool>("true"); 

로 호출하지만이 가능하다는 것을 알고 있습니다 질문에서 분명하지 않다.

물론 당신이하는 일이 정말로 일반적인 것이 아니기 때문에 (그리고 당신이 분석하고자하는 각각의 유형을 전문화해야한다.) 그런 다음 템플릿을 작성하는 것은 어쨌든 옳은 일이 아니다. 그런데

, 당신은 같은 하나의 기능으로 꽤 일반적으로 그것을 할 수 있습니다 (가정 구문 분석 당신이 정말로 원하는 것입니다) :

#include <sstream> 
template<typename T> T parse(const string& str) 
{ 
    T t; 
    std::istringstream sstr(str); 
    sstr >> t; 
    return t; 
} 

이 어떤 기본-constructable, 시냇물을 위해 작동합니다 추출 가능한 유형으로 모든 내장 기능을 포함합니다.

+0

이것은 "int parse_int (const string &)", "double parse_double (const string &)"등보다 훨씬 낫습니다. –

+3

그래서 템플릿으로 할 수 있다는 것을 보여 주었고 템플릿이 실제로 제네릭이 아닌 경우에는 템플릿을 사용하여 일반 (많은 유형의 경우)이 될 수있는 방법을 보여 줬습니다. –

+0

+1 -이 방법으로이 문제를보다 잘 정의 할 수 있습니다. –

0

C++에서는 이러한 유형의 동작을 수행 할 수 없습니다. 허용 될 수 있도록 반환 유형에 의해서만 다른 동일한 범위에서 동일한 이름의 함수를 정의 할 수 있어야합니다. 이것은 C++에서는 유효하지 않습니다.

C++은 재정의 된 가상 함수에서 공변 반환 유형과 같은 일부 반환 유형 특수화를 수행 할 수 있습니다. 그러나 그것은 당신이 찾고있는 것을 지원하지 않습니다.

+0

기술적으로 C++의 반환 유형으로 오버로드 할 수는 없지만 사용자 정의 변환을 사용하면 거의 동일한 결과를 얻을 수 있습니다. litb의 뛰어난 대답을 참조하십시오. . –

5

출력 인수를 포인터 또는 참조로 전달할 수 있습니다.이처럼

이 같은

template<class T> void parse(const std::string &input, T& output); 

다음 코드 :

double d; parse(input, d); 
int i; parse(input, i); 

작동합니다. 당신은 다소 복잡한 서식이 포함 된 경우

istringstream is(input); 
input >> d; 

, 트릭 내가 있었다 꽤 행운을 만드는 작업이 포함됩니다 함께 :

그러나 코드는 것 성병 :: istringstream에 매우 적합처럼 보인다 데이터를 추출하는 사용자 정의 연산자 >>가있는 사용자 정의 객체. 이

struct proxy { 
    string str; 
    proxy(string const &str):str(str) { } 
    template<typename T> operator T() { 
     return boost::lexical_cast<T>(str); 
    } 
}; 

proxy parse(string const &str) { return proxy(str); } 

지금 방금

float a = parse("3.1"); 

을 할 필요가 변환 기능을 수행 할 수 있습니다

istringstring is(input); 
input >> LineExtracter(x, y, d); 
3

변환하지 않습니다. 캐스팅 연산자를 사용하십시오.

#include <iostream> 
#include <string> 
#include <sstream> 

class Convertible 
{ 
public: 
    int m_Integer; 
    bool m_Bool; 
    double m_Double; 

    Convertible() : m_Integer(0), m_Bool(false), m_Double(0.0) {}; 

    operator int() const 
    { 
     return m_Integer; 
    } 
    operator bool() const 
    { 
     return m_Bool; 
    } 
    operator double() const 
    { 
     return m_Double; 
    } 
}; 

Convertible parse(std::string data) 
{ 
    Convertible l_result; 

    std::istringstream converter(data); 
    converter >> l_result.m_Integer; 

    std::istringstream converter2(data); 
    converter2 >> l_result.m_Bool; 

    std::istringstream converter3(data); 
    converter3 >> l_result.m_Double; 

    return l_result; 
} 

void main() 
{ 
    int l_convertedInt = parse("2"); 
    bool l_convertedBool = parse("true"); 
    double l_convertedDouble = parse("3.14"); 

    std::cout << "Converted '2' to " << l_convertedInt << std::endl; 
    std::cout << "Converted 'true' to " << l_convertedBool << std::endl; 
    std::cout << "Converted '3.14' to " << l_convertedDouble << std::endl; 
} 
0

여기 parse()에 인수가 문자열이 아닌 다른 유형의 내 상황에 대한 @Tyler McHenry's answer 내 적응이다. 나는이 형식 변환 경고 (intfloat)를 방지하기 위해 템플릿 특수화을 소개했다 발견

참고.

#include <iostream> 

struct MyUnion 
{ 
public: 
    union { 
    bool bool_value; 
    int int_value; 
    float float_value; 
    }; 
}; 

template<typename T> T parse(const MyUnion& h) 
{ 
    T t; 

    if (typeid(T) == typeid(bool)) { 
    t = h.bool_value; 
    } else if (typeid(T) == typeid(int)) { 
    t = h.int_value; 
    } else if (typeid(T) == typeid(float)) { 
    // t = h.float_value; // see **Warning** below; use float specialization instead 
    } 

    return t; 
} 

// 'float' template specialization to avoid conversion warning. 
template<> float parse(const MyUnion& h) 
{ 
    return h.float_value; 
} 

int main() 
{ 
    MyUnion mu1; mu1.bool_value = true; 
    MyUnion mu2; mu2.int_value = 42; 
    MyUnion mu3; mu3.float_value = 3.14159; 

    std::cout << "As bool: " << parse<bool>(mu1) << std::endl; 
    std::cout << "As int: " << parse<int>(mu2) << std::endl; 
    std::cout << "As float: " << parse<float>(mu3) << std::endl; 
} 

// **Warning** 
// In function 'T parse(const Heterogeneous&) [with T = int]': 
// Line 22: warning: converting to 'int' from 'const float'