#include <iostream>
#include <memory>
#include <string>


struct IHandle {
	virtual ~IHandle(void) {}
	virtual std::string const & GetName(void) const = 0;
};


template <typename T> struct Handle : IHandle {
	explicit Handle(std::shared_ptr<T> const & body) : mBody(body) {}
	std::string const & GetName(void) const { return mBody->GetName(); }
private:
	std::shared_ptr<T> mBody;
};


struct IFoo {
	virtual ~IFoo(void) {}
	template <typename T> void NVMethod(std::shared_ptr<T> const & body) {
		VMethod(Handle<T>(body));
	}
protected:
	virtual void VMethod(IHandle const & handle) = 0;
};


struct FooEx1 : IFoo {
protected:
	void VMethod(IHandle const & handle) {
		std::cout << "引数の名前は " << handle.GetName() << " です。" << std::endl;
	}
};


struct FooEx2 : IFoo {
protected:
	void VMethod(IHandle const & handle) {
		std::cout << "The name of argument is " << handle.GetName() << "." << std::endl;
	}
};


struct Argument1 {
	Argument1(std::string const & name) : mName(name) { }
	std::string const & GetName(void) const {
		return mName;
	}
private:
	std::string mName;
};


struct Argument2 {
	Argument2(std::string const & name = std::string()) : mName(name) { }
	std::string const & GetName(void) const {
		static std::string const anon("Anon");
		return mName.empty() ? anon : mName;
	}
private:
	std::string mName;
};


int main(void) {
	std::shared_ptr<IFoo> p;

	p = std::make_shared<FooEx1>();
	p->NVMethod(std::make_shared<Argument1>("Bob"));
	
	p = std::make_shared<FooEx2>();
	p->NVMethod(std::make_shared<Argument2>());

	return 0;
}
