문제

내 템플릿 클래스 정의된 헤더 파일에 다음과 같다.여기에서 내가 정의되는 정적 변수 뿐만 아니라:

#ifndef TEST1_H_
#define TEST1_H_

void f1();

static int count;

template <class T>
class MyClass
{
public:

    void f()
    {
        ++count;
    }


};

#endif

고 나는 정의는 main()함수에서 다른 cpp 파일에 다음과 같다:

int main(int argc, char* argv[])
{
    MyClass<int> a;
    a.f();
    f1();

    cout<<"Main:" << count << "\n";

    return 0;
}

내가 구현한 기능 f1()다른 cpp 파일에 다음과 같다:

void f1()
{
    MyClass<int> a;
    a.f();

    cout<<"F1: " <<count <<"\n";
}

때 나는 컴파일을 사용하여 이를 VC6,나는 출력으로"F1:0 홈페이지:2".어떻게 이런 일이 가능합니까?또한,일반적으로 어떻게 처리해야 하고 싶은 경우에 사용하는 정적 변수와 함께 템플릿?

도움이 되었습니까?

해결책

헤더 파일에서 정적 변수를 선언했기 때문에 동일한 변수의 두 사본을 얻을 수 있습니다. 글로벌 변수를 선언 할 때 static 이런 식으로, 당신은 그것이 컴파일 장치에 로컬이라고 말하고 있습니다 ( .o 파일). 두 개의 컴파일 장치에 헤더를 포함하므로 2 개의 사본을 얻을 수 있습니다. count.

나는 당신이 여기서 정말로 원하는 것이 각각과 관련된 정적 템플릿 멤버 변수라고 생각합니다. 사례 템플릿 클래스의. 다음과 같습니다.

template <class T>
class MyClass
{
    // static member declaration
    static int count;
    ...
};

// static member definition
template<class T> int MyClass<T>::count = 0;

이렇게하면 템플릿의 각 인스턴스화마다 계산됩니다. 즉, 당신은 카운트를 가질 것입니다 MyClass<int>, MyClass<foo>, MyClass<bar>, 등. f1() 이제 다음과 같이 보일 것입니다.

void f1() {
    MyClass<int> a;
    a.f();

    cout<<"F1: " << MyClass<int>::count <<"\n";
}

당신이 카운트를 원한다면 모두 MyClass의 인스턴스화 (템플릿 매개 변수에 관계없이) 글로벌 변수.

그러나 초기화되기 전에 사용될 위험이 있기 때문에 글로벌 변수를 직접 원하지 않을 것입니다. 카운트에 대한 참조를 반환하는 글로벌 정적 메소드를 만들어이 문제를 해결할 수 있습니다.

int& my_count() {
    static int count = 0;
    return count;
}

그런 다음 다음과 같이 수업 내에서 액세스하십시오.

void f() {
    ++my_count();
}

이렇게하면 Count가 사용하기 전에 카운트가 초기화되도록합니다. 참조 정적 초기화 순서의 C ++ FAQ 자세한 사항은.

다른 팁

정적 선언을 헤더 파일에 넣으면 각 .cpp 파일이 자체 버전의 변수를 얻게됩니다. 따라서 두 Cout 문은 다른 변수를 인쇄하고 있습니다.

"F1 : 1 Main : 1"을 기대 했습니까? 당신은 인스턴스화했습니다 MyClass<int> 두 개의 개별 번역 단위 (즉, 두 개의 객체 파일)에서 링커는 중복 템플릿 인스턴스화가 있음을 알았으므로 인스턴스화를 폐기했습니다. f1객체 파일.

당신은 지나가고 있습니까? /OPT:ICF 또는 /OPT:REF VC6 링커에? 이는 중복 템플릿 인스턴스턴스 제거와 관련이있을 수 있습니다 (또는 중복 템플릿 인스턴스열은 일반적인 중복 함수와 비교하여 특별한 경우 일 수 있음). GCC가하는 것 같습니다 비슷한 것 일부 플랫폼에서.

어쨌든, 나는이 행동이 컴파일러에 걸쳐 일관되게 의존하지 않을 것입니다. 또한 링커 명령 줄에서 객체 파일 순서를 변경하면 어떤 인스턴스가 폐기되는지에 영향을 줄 수 있습니다.

다른 솔루션이 있습니다. 공유 부모 클래스를 만들고이 정적 변수를 넣은 다음 템플릿 클래스를 개인적으로 상속하게 만들 수 있습니다. 예를 들어 있습니다.

class Parent
{
protected: 
    static long count;
};

long Parent::count = 0;

template<typename T>
class TemplateClass: private Parent
{
private: 
    int mKey;
public:
    TemplateClass():mKey(count++){}
    long getKey(){return mKey;}
}

int main()
{
    TemplateClass<int> obj1;
    TemplateClass<double> obj2;

    std::cout<<"Object 1 key is: "<<obj1.getKey()<<std::endl;
    std::cout<<"Object 2 key is: "<<obj2.getKey()<<std::endl;

    return 0;
}

출력은 다음과 같습니다.

Object 1 key is: 0 
Object 2 key is: 1

내 생각에 이것은 실제로 정의되지 않은 행동.

에 따라 C++14[기본입니다.def.odr]/6:

가될 수 있는 하나 이상의 정의[...]멤버의 기능을 템플릿 클래스[...]프로그램에서 제공하는 각각의 정의에 나타나 다른 번역 유닛,그리고 제공하의 정의는 다음 요구 사항을 충족.주 같은 엔터티라는 이름 D 에 정의된 하나 이상의 번역 단위,다음

  • 각각의 정의 D 로 이루어져 있을 것 같은 시퀀스의 토큰;고
  • 에서 각각의 정의 D,해당 이름에 따라 3.4 하며,참조하 엔터티 내에서 정의의 정의 D 나를 참조할 것 같은 엔터티를 한 후,과부하도(13.3)후 일치하는 부분의 템플릿을 전문화(14.8.3)는 것을 제외하고,이름을 참조할 수 있는 비 휘발성 const 체와 내부 또는 결합하는 경우 객체에는 동일한 유형 리터럴에서의 모든 정의 D,및 개체을 초기화 일정과 표현(5.19),그리고 객체지 않 odr 사용되는,그리고 객체가 동일한 값에서의 모든 정의 D[...]

문제는 처음에 .cpp 파일 이름 countf1 말을 다른 개체보다는 이름 countf1 에서 두 번째 .cpp 파일,따라서을 위반하는 조건에 해당 이름을 참조해야입니다.

그들은 다른 객체를 때문에 static 지정자는 그 각각의 번역 유닛 그 자체로는 이름입니다.

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