我希望能够使用一些默认值初始化对象,但是要从外部代码(不嵌入类本身)中执行此操作。对象暴露给外部编辑器,我不想一次又一次地设置相同的值,只更改一些不同的值。由于我已经有模板类,我想从“traits”类中做到这一点。
这是我想要实现的简单描述:
template<typename Traits>
class Test
{
public:
Test()
{
//if Traits has Init init function call Traits::Init(this)
}
private:
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 = 0;
}
};
int main()
{
Test<TestTraits> obj1;
Test<TestTraitsInit> obj2;
}
正如您所看到的,仅在某些情况下使用Init()
是有意义的。 是否可以检查班级Traits
是否具有Init()
功能并仅在其存在时调用?
我知道一个非常简单的解决方案是使用空Init()
函数,但我想要一个更好的解决方案:)
答案 0 :(得分:3)
您可以根据表达式SFINAE创建一些具有SFINAE约束专业化的类模板maybe_call_init
:
template<typename T, typename = void>
struct maybe_call_init
{
static void maybe_call(Test<T>* obj) { }
};
template<typename T>
struct maybe_call_init<T,
decltype(T::Init(std::declval<Test<T>*>()), void(0))>
{
static void maybe_call(Test<T>* obj) { T::Init(obj); }
};
给定特征T
,如果maybe_call_init<T>::maybe_call(obj)
定义了这样的函数,T::Init(obj)
将调用T
,否则它将不执行任何操作。
然后,您可以这样在原始类模板中使用它:
template<typename Traits>
class Test
{
public:
Test()
{
maybe_call_init<Traits>::maybe_call(this);
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
}
private:
typename Traits::Type value;
friend Traits;
};
上面的解决方案有点基础,可以通过将maybe_call_init
类模板及其特化隐藏在detail
命名空间中来提高,提供辅助函数来进行实例化工作。所以考虑到这个机器:
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);
}
原始Test
类的构造函数现在看起来像这样:
template<typename Traits>
class Test
{
public:
Test()
{
maybe_call_init(this);
// ^^^^^^^^^^^^^^^^^^^^^
}
public:
typename Traits::Type value;
friend Traits;
};
这是live example。