CRTP & typedef による型の追加と継承の相性
boost::add_pointer のようなことをやりたいと思い,
#include <iostream> #include <tr1/memory> template <typename T> class Pointable { public: typedef std::tr1::shared_ptr<T> ptr_t; }; class Parent : public Pointable<Parent> { public: Parent() { std::cout << "Parent created" << std::endl; } ~Parent() { std::cout << "Parent deleted" << std::endl; } }; class Child : public Pointable<Child>, public Parent { public: Child() { std::cout << "Child created" << std::endl; } ~Child() { std::cout << "Child deleted" << std::endl; } }; int main(int argc, char **argv) { Child::ptr_t child_ptr(new Child()); Parent::ptr_t parent_ptr(new Parent()); return 0; }
をコンパイルすると,
pointable.cc:39:12: error: member 'ptr_t' found in multiple base classes of different types Child::ptr_t child_ptr(new Child()); ^ pointable.cc:8:37: note: member found by ambiguous name lookup typedef std::tr1::shared_ptr<T> ptr_t; ^ pointable.cc:8:37: note: member found by ambiguous name lookup 1 error generated.
というエラーが出てしまう(clang++).
次のように,各クラス内で明示的にポインタ型を typedef してあげれば,当然ながらコンパイルできる.しかし,元々の目的はこの冗長さを取り除くことにあったので,できれば上記のように CRTP などを用いたい.
class Parent { public: typedef std::tr1::shared_ptr<Parent> ptr_t; Parent() { std::cout << "Parent created" << std::endl; } ~Parent() { std::cout << "Parent deleted" << std::endl; } }; class Child : public Parent { public: typedef std::tr1::shared_ptr<Child> ptr_t; Child() { std::cout << "Child created" << std::endl; } ~Child() { std::cout << "Child deleted" << std::endl; } };
何かよい解決策はないものだろうか.
追記
C++ 人脈に乏しいため Stackoverflow 様にお頼り申し上げた.返信は来るかな?
http://stackoverflow.com/questions/9114959/typedef-with-crtp-doesnt-work-when-inheritance-is-used
追記2
わー,返信が頂けたよ.
Your problem has nothing to do with the CRTP, but with multiple inheritance. Child inherits ptr_t from both its base classes, and both types are different: shared_ptr
vs. shared_ptr . Therefore, the compiler cannot figure out which type you mean by Child::ptr_t in main. As you pointed out, you have to fix this manually using a typedef in Child (making your Pointable base class useless, though).
class Child : public Parent, public Pointable<Child> { public: typedef Pointable<Child>::ptr_t ptr_t;http://stackoverflow.com/questions/9114959/typedef-with-crtp-doesnt-work-when-inheritance-is-used
ああ,そうか,多重継承をしているためであったのね.理解した.
追記3
ちなみに,上記の回答で
class Child : public Parent, public Pointable<Child> { public: typedef Pointable<Child>::ptr_t ptr_t;
というコードを教えて頂いているが,こちらも少し冗長ではあるが実際の定義である shared_ptr
を取り除くことができており DRY の原則には反していないので OK だろう.勉強になったなあ.
こちらについては,次のページも参照のこと.いやあ Stack Overflow さまさま.