#include <string>
#include <utility>
#include <functional>
#include <iostream>
namespace detail
{
template<typename T, typename U, typename = void>
struct maybe_call_init
{
static void maybe_call(U* obj) { }
};
template<typename T, typename U>
struct maybe_call_init<T, U,
decltype(T::Init(std::declval<U*>()), void(0))>
{
static void maybe_call(U* obj) { T::Init(obj); }
};
}
template<template<typename> class T, typename U>
void maybe_call_init(T<U>* obj)
{
detail::maybe_call_init<U, T<U>>::maybe_call(obj);
}
template<typename Traits>
class Test
{
public:
Test()
{
maybe_call_init(this);
}
public:
typename Traits::Type value;
friend Traits;
};
struct TestTraits
{
typedef std::string Type;
};
struct TestTraitsInit
{
typedef int Type;
static void Init(Test<TestTraitsInit>* obj)
{
obj->value = 42;
}
};
int main()
{
Test<TestTraits> obj1;
std::cout << "Value of obj1: " << obj1.value << std::endl;
Test<TestTraitsInit> obj2;
std::cout << "Value of obj2: " << obj2.value << std::endl;
}
ICAgICNpbmNsdWRlIDxzdHJpbmc+CiAgICAjaW5jbHVkZSA8dXRpbGl0eT4KICAgICNpbmNsdWRlIDxmdW5jdGlvbmFsPgogICAgI2luY2x1ZGUgPGlvc3RyZWFtPgoKICAgIG5hbWVzcGFjZSBkZXRhaWwKICAgIHsKICAgICAgICB0ZW1wbGF0ZTx0eXBlbmFtZSBULCB0eXBlbmFtZSBVLCB0eXBlbmFtZSA9IHZvaWQ+CiAgICAgICAgc3RydWN0IG1heWJlX2NhbGxfaW5pdAogICAgICAgIHsKICAgICAgICAgICAgc3RhdGljIHZvaWQgbWF5YmVfY2FsbChVKiBvYmopIHsgfQogICAgICAgIH07CgogICAgICAgIHRlbXBsYXRlPHR5cGVuYW1lIFQsIHR5cGVuYW1lIFU+CiAgICAgICAgc3RydWN0IG1heWJlX2NhbGxfaW5pdDxULCBVLAogICAgICAgICAgICBkZWNsdHlwZShUOjpJbml0KHN0ZDo6ZGVjbHZhbDxVKj4oKSksIHZvaWQoMCkpPgogICAgICAgIHsKICAgICAgICAgICAgc3RhdGljIHZvaWQgbWF5YmVfY2FsbChVKiBvYmopIHsgVDo6SW5pdChvYmopOyB9CiAgICAgICAgfTsKICAgIH0KCiAgICB0ZW1wbGF0ZTx0ZW1wbGF0ZTx0eXBlbmFtZT4gY2xhc3MgVCwgdHlwZW5hbWUgVT4KICAgIHZvaWQgbWF5YmVfY2FsbF9pbml0KFQ8VT4qIG9iaikKICAgIHsKICAgICAgICAgZGV0YWlsOjptYXliZV9jYWxsX2luaXQ8VSwgVDxVPj46Om1heWJlX2NhbGwob2JqKTsKICAgIH0KCiAgICB0ZW1wbGF0ZTx0eXBlbmFtZSBUcmFpdHM+CiAgICBjbGFzcyBUZXN0CiAgICB7CiAgICAgICAgcHVibGljOgogICAgICAgICAgICBUZXN0KCkKICAgICAgICAgICAgewogICAgICAgICAgICAgICAgbWF5YmVfY2FsbF9pbml0KHRoaXMpOwogICAgICAgICAgICB9CgogICAgICAgIHB1YmxpYzoKICAgICAgICAgICAgdHlwZW5hbWUgVHJhaXRzOjpUeXBlIHZhbHVlOwoKICAgICAgICBmcmllbmQgVHJhaXRzOwogICAgfTsKCiAgICBzdHJ1Y3QgVGVzdFRyYWl0cwogICAgewogICAgICAgIHR5cGVkZWYgc3RkOjpzdHJpbmcgVHlwZTsKICAgIH07CgogICAgc3RydWN0IFRlc3RUcmFpdHNJbml0CiAgICB7CiAgICAgICAgdHlwZWRlZiBpbnQgVHlwZTsKCiAgICAgICAgc3RhdGljIHZvaWQgSW5pdChUZXN0PFRlc3RUcmFpdHNJbml0Piogb2JqKQogICAgICAgIHsKICAgICAgICAgICAgb2JqLT52YWx1ZSA9IDQyOwogICAgICAgIH0KICAgIH07CgogICAgaW50IG1haW4oKQogICAgewogICAgICAgIFRlc3Q8VGVzdFRyYWl0cz4gb2JqMTsKICAgICAgICBzdGQ6OmNvdXQgPDwgIlZhbHVlIG9mIG9iajE6ICIgPDwgb2JqMS52YWx1ZSA8PCBzdGQ6OmVuZGw7CiAgICAgICAgVGVzdDxUZXN0VHJhaXRzSW5pdD4gb2JqMjsKICAgICAgICBzdGQ6OmNvdXQgPDwgIlZhbHVlIG9mIG9iajI6ICIgPDwgb2JqMi52YWx1ZSA8PCBzdGQ6OmVuZGw7CiAgICB9Cg==