Во-первых, Set()
подходит для любого базового типа, POD или агрегатного типа класса, так как последние типы классов будут иметь оператор присваивания по умолчанию, который делает то, что вам нужно.
Единственный вопрос:как звонить Foo()
.К счастью, у нас есть черты типа, чтобы справиться с этим, а именно: std::is_fundamental
.
#include <type_traits>
template <typename T> struct S
{
T val;
// Base case: call member `Foo()`.
template <typename U, bool Primitive, bool Array> struct callFoo
{
static void call(const U & u) { u.Foo(); }
};
// Specialization for primitive types (implement this yourself)
template <typename U> struct callFoo<U, true, false>
{
static void call(U u) { /* fundamental implementation here */ }
};
// Specialization for arrays: call `Foo()` on every element.
template <typename U> struct callFoo<U, false, true>
{
typedef typename std::remove_extent<U>::type V;
template <std::size_t N>
static void call(const V (&arr)[N])
{
for (std::size_t i = 0; i != N; ++i)
{
callFoo<V, std::is_fundamental<V>::value, std::is_array<V>::value>::call(arr[i]);
}
}
};
void Foo()
{
callFoo<T, std::is_fundamental<T>::value, std::is_array<T>::value>::call(val);
}
};
(Некоторые незначительные вещи: вы можете захотеть сделать callFoo
приватным. И подумайте также о константности: если применимо,сделать callFoo
и Foo` постоянными.)