문제

오늘 내 질문은 매우 간단합니다. 컴파일러가 기능 매개 변수에서 할 수있는 것처럼 클래스 생성자의 템플릿 매개 변수가 왜 할 수 없는가? 예를 들어, 다음 코드가 유효하지 않은 이유는 다음과 같습니다.

template<typename obj>
class Variable {
      obj data;
      public: Variable(obj d)
              {
                   data = d;
              }
};

int main()
{
    int num = 2;
    Variable var(num); //would be equivalent to Variable<int> var(num),
    return 0;          //but actually a compile error
}

내가 말했듯이, 나는 이것이 유효하지 않다는 것을 이해하므로 내 질문은 그렇지 않습니까? 이것을 허용하면 주요 구문 구멍이 생길까요? 이 기능을 원하지 않는 인스턴스가 있습니까 (유형을 유추하면 문제가 발생할 수있는 곳)가 있습니까? 나는 단지 기능에 대한 템플릿 추론을 허용하는 논리를 이해하려고 노력하고 있지만 적절하게 구성된 클래스는 아닙니다.

도움이 되었습니까?

해결책

생성자가 항상 클래스의 유일한 진입 지점이 아니기 때문에 유효하지 않다고 생각합니다 (복사 생성자 및 연산자 =). 따라서 다음과 같이 수업을 사용한다고 가정 해 봅시다.

MyClass m(string s);
MyClass *pm;
*pm = m;

파서가 어떤 템플릿 유형인지 MyClass PM인지 알 수 있는지 확실하지 않습니다.

내가 말한 것이 이해가되지만 의견을 추가하면 확실하지 않습니다. 그것은 흥미로운 질문입니다.

C ++ 17

C ++ 17은 생성자 인수로부터 유형 공제를 가질 것입니다.

예 :

std::pair p(2, 4.5);
std::tuple t(4, 3, 2.5);

받아 들여진 종이.

다른 팁

다른 사람들이 해결 한 이유로 당신은 당신이 묻는 것을 할 수 없지만, 당신은 이것을 할 수 있습니다.

template<typename T>
class Variable {
    public: Variable(T d) {}
};
template<typename T>
Variable<T> make_variable(T instance) {
  return Variable<T>(instance);
}

모든 의도와 목적을 위해 당신이 요구하는 것과 동일합니다. 캡슐화를 좋아하면 make_variable을 정적 멤버 함수로 만들 수 있습니다. 그것이 사람들이 명명 된 생성자라고 부르는 것입니다. 따라서 원하는대로 할뿐만 아니라 원하는 것을 거의 불러냅니다. 컴파일러는 (명명 된) 생성자의 템플릿 매개 변수를 추론합니다.

NB : 모든 합리적인 컴파일러는 다음과 같은 글을 쓸 때 임시 객체를 최적화합니다.

Variable<T> v = make_variable(instance);

2016 년의 깨달은 나이에,이 질문이 요청 된 이후로 우리의 벨트 아래에 두 가지 새로운 표준이 있고 모퉁이를 돌면 새로운 표준이 있습니다. 알아야 할 중요한 점은 C ++ 17 표준을 지원하는 컴파일러 코드를 AS- 컴파일하십시오.

C ++ 17의 클래스 템플릿에 대한 템플릿 관절 공제

여기 (허용 된 답변의 Olzhas Zhumabek의 편집 제공)는 표준의 관련 변경 사항을 자세히 설명하는 논문입니다.

다른 답변의 우려를 해결합니다

현재 최고 등급의 답변

이 답변은 "복사 생성자와 operator="올바른 템플릿 전문화를 모를 것입니다.

표준 카피-건설자와 operator= 만 존재합니다 a 모두 다 아는 템플릿 유형 :

template <typename T>
class MyClass {
    MyClass(const MyClass&) =default;
    ... etc...
};

// usage example modified from the answer
MyClass m(string("blah blah blah"));
MyClass *pm;   // WHAT IS THIS?
*pm = m;

여기에 내가 의견에서 언급했듯이 이유없이 ~을 위한 MyClass *pm 새로운 형태의 추론 유무에 관계없이 법적 선언이 되려면 : MyClass 유형이 아닙니다 (템플릿입니다) 따라서 유형의 포인터를 선언하는 것은 의미가 없습니다. MyClass. 예제를 수정하는 가능한 한 가지 방법은 다음과 같습니다.

MyClass m(string("blah blah blah"));
decltype(m) *pm;               // uses type inference!
*pm = m;

여기, pm ~이다 이미 올바른 유형의 경우 추론이 사소합니다. 또한 우연히 불가능합니다 혼합 유형 카피-건설자를 호출 할 때 :

MyClass m(string("blah blah blah"));
auto pm = &(MyClass(m));

여기, pm 사본에 대한 포인터가 될 것입니다 m. 여기, MyClass 카피로 구성되고 있습니다 m- 유형입니다 MyClass<string> (그리고 ~ 아니다 존재하지 않는 유형의 MyClass). 따라서 어디에서 pm유형의 유형이 추론됩니다 ~이다 템플릿 유형을 알 수있는 충분한 정보 m, 따라서 템플릿 유형의 pm, 이다 string.

또한 다음의 의지 언제나 컴파일 오류를 높이십시오:

MyClass s(string("blah blah blah"));
MyClass i(3);
i = s;

사본 생성자의 선언이 ~ 아니다 템플릿 :

MyClass(const MyClass&);

여기서는 카피-구성 인수의 템플릿 유형입니다 성냥 전체 클래스의 템플릿 유형; 즉, 언제 MyClass<string> 인스턴스화되고 MyClass<string>::MyClass(const MyClass<string>&); 그것으로 인스턴스화됩니다 MyClass<int> 인스턴스화되고 MyClass<int>::MyClass(const MyClass<int>&); 인스턴스화됩니다. 명시 적으로 지정되거나 템플릿 생성자가 선언되지 않는 한, 컴파일러가 인스턴스화 할 이유가 없습니다. MyClass<int>::MyClass(const MyClass<string>&);, 분명히 부적절 할 것입니다.

CĂtĂlin Pitiș의 답변

Piti로는 예제를 추론합니다 Variable<int> 그리고 Variable<double>, 다음 :

두 가지 유형 (변수 및 변수)에 대한 코드에 동일한 유형 이름 (변수)이 있습니다. 주관적인 관점에서 볼 때 코드의 가독성에 거의 영향을 미칩니다.

이전 예에서 언급했듯이 Variable 그 자체입니다 ~ 아니다 유형 이름은 새로운 기능이 구문 적으로 하나처럼 보이지만 유형 이름입니다.

그런 다음 Piti로는 적절한 추론을 허용하는 생성자가 제공되지 않으면 어떻게 될지 묻습니다. 대답은 추론이 허용되지 않는다는 것입니다. 추론은 생성자 호출. 생성자 통신이 없으면 있습니다 추론이 없습니다.

이것은 어떤 버전의 버전을 묻는 것과 유사합니다 foo 여기에서 추론됩니다.

template <typename T> foo();
foo();

답은이 코드가 불법이라는 이유입니다.

Msalter의 답변

이것은 내가 알 수있는 한, 제안 된 기능에 대한 합법적 인 우려를 불러 일으키는 유일한 대답입니다.

예는 다음과 같습니다. 예는 다음과 같습니다.

Variable var(num);  // If equivalent to Variable<int> var(num),
Variable var2(var); // Variable<int> or Variable<Variable<int>> ?

주요 질문은 컴파일러가 유형에 포함됩니다 여기 또는 생성자 복사 건설자?

코드를 사용하여 사본 생성자가 선택되었음을 알 수 있습니다. 예에서 확장하려면:

Variable var(num);          // infering ctor
Variable var2(var);         // copy ctor
Variable var3(move(var));   // move ctor
// Variable var4(Variable(num));     // compiler error

제안과 표준의 새 버전이 어떻게이를 지정하는지 잘 모르겠습니다. "공제 안내서"에 의해 결정된 것으로 보이며, 이는 아직 이해하지 못하는 새로운 표준입니다.

나는 또한 왜 그런지 잘 모르겠습니다 var4 공제는 불법입니다. g ++의 컴파일러 오류는 진술이 함수 선언으로 구문 분석되고 있음을 나타냅니다.

아직 누락 : 다음 코드가 매우 모호합니다.

int main()
{
    int num = 2;
    Variable var(num);  // If equivalent to Variable<int> var(num),
    Variable var2(var); //Variable<int> or Variable<Variable<int>> ?
}

컴파일러가 요청한 내용을 지원한다고 가정합니다. 그런 다음이 코드는 유효합니다.

Variable v1( 10); // Variable<int>

// Some code here

Variable v2( 20.4); // Variable<double>

이제 두 가지 유형 (변수 및 변수)에 대한 코드에 동일한 유형 이름 (변수)이 있습니다. 주관적인 관점에서 볼 때 코드의 가독성에 거의 영향을 미칩니다. 같은 네임 스페이스에서 두 가지 다른 유형에 대해 동일한 유형 이름을 갖는 것은 나에게 오해의 소지가 있습니다.

나중에 업데이트 :고려해야 할 또 다른 사항 : 부분적 (또는 전체) 템플릿 전문화.

가변을 전문화하고 예상 한 것처럼 생성자를 제공하지 않으면 어떻게됩니까?

그래서 나는 가질 것이다 :

template<>
class Variable<int>
{
// Provide default constructor only.
};

그런 다음 코드가 있습니다.

Variable v( 10);

컴파일러는 무엇을해야합니까? 일반 변수 클래스 정의를 사용하여 변수가 가변적이라고 추론 한 다음 변수가 하나의 매개 변수 생성자를 제공하지 않는다는 것을 발견하십시오.

C ++ 03 및 C ++ 11 표준은 전달 된 매개 변수로부터 템플릿 인수 공제를 허용하지 않습니다.

그러나 "생성자에 대한 템플릿 매개 변수 공제"에 대한 제안이 있으므로 곧 요구하는 것을 얻을 수 있습니다. 편집 : 실제로이 기능은 C ++ 17에 대해 확인되었습니다.

보다: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3602.html 그리고 http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/p0091r0.html

많은 클래스가 생성자 매개 변수에 의존하지 않습니다. 생성자가 하나만 있고이 생성자의 유형을 기준으로 매개 변수화하는 클래스는 몇 개뿐입니다.

템플릿 추론이 실제로 필요한 경우 헬퍼 기능을 사용하십시오.

template<typename obj>
class Variable 
{
      obj data;
public: 
      Variable(obj d)
      : data(d)
      { }
};

template<typename obj>
inline Variable<obj> makeVariable(const obj& d)
{
    return Variable<obj>(d);
}

유형의 공제는 현재 C ++의 템플릿 함수로 제한되지만 다른 상황에서 유형 공제가 매우 유용하다는 것이 오랫동안 실현되었습니다. 따라서 C ++ 0x auto.

하는 동안 바로 그거죠 C ++ 0X에서는 제안 된 내용이 불가능합니다. 다음 쇼는 매우 가까워 질 수 있습니다.

template <class X>
Variable<typename std::remove_reference<X>::type> MakeVariable(X&& x)
{
    // remove reference required for the case that x is an lvalue
    return Variable<typename std::remove_reference<X>::type>(std::forward(x));
}

void test()
{
    auto v = MakeVariable(2); // v is of type Variable<int>
}

컴파일러는 쉽게 추측 할 수 있지만, 내가 아는 한 표준 또는 C ++ 0x에 있지 않으므로 컴파일러 제공 업체 가이 기능을 추가하기 전에 10 년 더 이상 10 년 더 기다려야합니다 (ISO 표준 고정 턴 턴트)

모든 사람이 -std :: 벡터와 유사 해야하는 수업을 참조하여 문제를 살펴 보겠습니다.

첫째, 벡터의 매우 일반적인 사용은 매개 변수를 사용하지 않는 생성자를 사용하는 것입니다.

vector <int> v;

이 경우 분명히 추론을 수행 할 수 없습니다.

두 번째 일반적인 사용은 미리 크기의 벡터를 만드는 것입니다.

vector <string> v(100);

여기에서 추론이 사용 된 경우 :

vector v(100);

우리는 문자열이 아닌 ints의 벡터를 얻을 수 있으며 아마도 크기는 아니다!

마지막으로 "추론"을 사용하여 여러 매개 변수를 취하는 생성자를 고려하십시오.

vector v( 100, foobar() );      // foobar is some class

추론에 어떤 매개 변수를 사용해야합니까? 컴파일러가 두 번째로 컴파일러가되어야한다고 말하는 방법이 필요합니다.

벡터만큼 단순한 클래스의 이러한 모든 문제가 있으므로 추론이 사용되지 않는 이유를 쉽게 알 수 있습니다.

CTOR를 템플릿으로 만드는 것은 변수를 가질 수 있습니다. 형태 그러나 다양한 CTORS :

class Variable {
      obj data; // let the compiler guess
      public:
      template<typename obj>
      Variable(obj d)
       {
           data = d;
       }
};

int main()
{
    int num = 2;
    Variable var(num);  // Variable::data int?

    float num2 = 2.0f;
    Variable var2(num2);  // Variable::data float?
    return 0;         
}

보다? 여러 변수 :: 데이터 멤버를 가질 수 없습니다.

보다 C ++ 템플릿 인수 공제 이에 대한 자세한 내용은.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top