문제

템플릿 인스턴스화를 사용하는 다음과 같은 문제가 있습니다 [*].

파일 foo.h

class Foo
{
public:
    template <typename F>
    void func(F f)

private:
    int member_;
};

파일 foo.cc

template <typename F>
Foo::func(F f)
{
     f(member_);
}

파일 발신자 .CC

Foo::func(boost::bind(&Bar::bar_func, bar_instance, _1));

이것은 정상적으로 컴파일하지만 링커는 정의되지 않은 기호에 대해 불평합니다.

void Foo::func<boost::_bi::bind_t...>

어떻게 인스턴스화 할 수 있습니까? 기능 Foo::func? 논쟁으로 기능을 취하기 때문에 약간 혼란 스럽습니다. 인스턴스화 함수를 추가하려고했습니다 foo.cc, 나는 정기적으로 익숙합니다 비 기능 유형 :

instantiate()
{
    template<> void Foo::func<boost::function<void(int)> >(boost::function<void(int)>);
}

분명히 이것은 작동하지 않습니다. 누군가가 나를 올바른 방향으로 가리킬 수 있다면 감사하겠습니다.

감사!

*] 예, Parashift FAQ Lite를 읽었습니다.

도움이 되었습니까?

해결책

이것에 대한 답은 컴파일러 종속입니다. SUN C ++ 컴파일러의 일부 버전은 별도의 번역 장치에서 공유되는 템플릿 기능 구현 캐시를 구축하여이를 자동으로 처리합니다.

Visual C ++ 및이를 수행 할 수없는 다른 컴파일러를 사용하는 경우 기능 정의를 헤더에 넣을 수도 있습니다.

헤더가 여러 .cc 파일에 포함 된 경우 중복 정의에 대해 걱정하지 마십시오. 컴파일러는 특수 속성으로 템플릿 생성 메소드를 표시하므로 링커는 불만 대신 중복을 버리는 것을 알고 있습니다. 이것이 C ++가 "하나의 정의 규칙"을 가진 이유 중 하나입니다.

편집하다: 위의 주석은 템플릿이 주어진 유형 매개 변수를 연결할 수 있어야하는 일반적인 경우에 적용됩니다. 클라이언트가 사용할 닫힌 유형 세트를 알고 있다면 템플릿의 구현 파일에서 명시적인 인스턴스화를 사용하여 고객이 사용할 수있게되므로 컴파일러가 다른 파일에 대한 정의를 생성 할 수 있습니다. 그러나 템플릿이 클라이언트에게만 알려진 유형으로 작동 해야하는 일반적인 경우 템플릿을 헤더 파일로 분리하고 구현 파일로 분리하는 데는 점이 거의 없습니다. 모든 고객은 어쨌든 두 부분을 모두 포함해야합니다. 클라이언트를 복잡한 종속성에서 분리하려면 비 모전 함수 뒤에 해당 종속성을 숨기고 템플릿 코드에서 호출하십시오.

다른 팁

원하는 것처럼 파일로 분할 :
나는 이것을 추천하지 않습니다. 가능하다는 것을 보여줍니다.

plop.h

#include <iostream>
class Foo
{
public:
    Foo(): member_(15){}


    // Note No definition of this in a header file.
    // It is defined in plop.cpp and a single instantiation forced
    // Without actually using it.
    template <typename F>
    void func(F f);

private:
    int member_;
};


struct Bar
{
     void bar_func(int val) { std::cout << val << "\n"; }
};

struct Tar
{
    void tar_func(int val) { std::cout << "This should not print because of specialisation of func\n";}
};

plop.cpp

#include "plop.h"
#include <boost/bind.hpp>
#include <iostream>

template <typename F>
void Foo::func(F f)
{
     f(member_);
}

// Gnarly typedef
typedef boost::_bi::bind_t<void, boost::_mfi::mf1<void, Bar, int>, boost::_bi::list2<boost::_bi::value<Bar>, boost::arg<1> (*)()> > myFunc;

// Force the compiler to generate an instantiation of Foo::func()
template void Foo::func<myFunc>(myFunc f);

// Note this is not a specialization as that requires the <> after template.
// See main.cpp for an example of specialization.

main.cpp

#include "plop.h"
#include <boost/bind.hpp>
#include <iostream>

// Gnarly typedef
typedef boost::_bi::bind_t<void, boost::_mfi::mf1<void, Tar, int>, boost::_bi::list2<boost::_bi::value<Tar>, boost::arg<1> (*)()> > myTar;

// Specialization of Foo::func()
template<> void Foo::func<myTar>(myTar f)
{
    std::cout << "Special\n";
}
// Note. This is not instantiated unless it is used.
// But because it is used in main() we get a version.

int main(int argc,char* argv[])
{
    Foo f;
    Bar b;
    Tar t;

    f.func(boost::bind(&Bar::bar_func, b, _1)); // Uses instantiation from plop.cpp
    f.func(boost::bind(&Tar::tar_func, t, _1)); // Uses local specialization
}

foo.cc를 caller.cc에 포함시키고 있습니까? 인스턴스화는 컴파일 시간에 발생하는 일입니다. 컴파일러가 호출자의 호출을 볼 때 템플릿의 인스턴스화 버전을 만들지 만 전체 정의를 사용할 수 있어야합니다.

나는 그들이 모두 언급하는 것은 템플릿 함수 정의 (선언뿐만 아니라)가 사용되는 파일에 포함되어야한다는 것입니다. 템플릿 기능은 실제로 사용될 때까지 존재하지 않습니다. 별도의 CC 파일에 넣으면 컴파일러는 다른 CC 파일에서 알지 못합니다. #include 이 CC 파일은 파서의 작동 방식으로 인해 헤더 파일 또는 호출되는 파일로 파일에 있습니다.

(earwicker가 설명한대로 템플릿 함수 정의가 일반적으로 헤더 파일에 보관되는 이유입니다.)

더 명확합니까?

나는 Earwicker가 정확하다고 생각합니다. 이 경우 템플릿 멤버 함수 기능을 명시 적으로 인스턴스화하는 문제는 boost :: bind가 구현 종속적이라는 것입니다. 그것은이다 ~ 아니다 부스트 :: 기능. 부스트 :: 기능이 가능합니다 포함하다 부스트 : 오른쪽 유형을 추론하는 템플릿 할당 연산자가 있기 때문에 바인딩하십시오 (부스트 :: 바인드 결과). Caller.cc에서 이러한 특별한 사용 에서이 특정 부스트를 구현하면 Boost :: Bind의 유형은 실제로 <및> (즉) 사이의 링커 오류에 언급 된 유형입니다. boost::_bi::bind_t...). 그러나 해당 유형의 기능을 명시 적으로 인스턴스화하면 휴대 성 문제가있을 수 있습니다.

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