您可以创建一个 init-time 函数表,以便该表的每个成员对应于您上面的一个案例语句。然后setSize 可以改用这个表。通过使用constexpr min 和 max 参数,您可以使用模板专业化指定此表的边界,并使用创建 Foo 对象的“制造商”函数的模板实例化填充它。
这里是函数表代码的声明(都在FooWrapper的private部分):
template<unsigned i>
static std::unique_ptr<IFoo> fooMaker()
{
return std::make_unique< Foo<i> >();
}
static constexpr unsigned FOO_MIN = 1;
static constexpr unsigned FOO_MAX = 3;
using FooMakerFn = std::unique_ptr<IFoo>();
template<unsigned min>
static std::array<FooMakerFn*, FOO_MAX-FOO_MIN-1>& initFooFnTable(std::array<FooMakerFn*, FOO_MAX-FOO_MIN-1>& fnTable);
static std::array<FooMakerFn*, FOO_MAX-FOO_MIN-1> fooFnTable;
这里是函数表创建的定义,包括终止case的特化:
std::array<FooWrapper::FooMakerFn*, FooWrapper::FOO_MAX-FooWrapper::FOO_MIN-1> FooWrapper::fooFnTable = FooWrapper::initFooFnTable<FooWrapper::FOO_MIN>(FooWrapper::fooFnTable);
template<unsigned min>
std::array<FooWrapper::FooMakerFn*, FooWrapper::FOO_MAX-FooWrapper::FOO_MIN-1>& FooWrapper::initFooFnTable(std::array<FooWrapper::FooMakerFn*, FooWrapper::FOO_MAX-FOO_MIN-1>& fnTable)
{
fnTable[min - FOO_MIN] = FooWrapper::fooMaker<min>;
return initFooFnTable<min+1>(fnTable);
}
template<>
std::array<FooWrapper::FooMakerFn*, FooWrapper::FOO_MAX-FooWrapper::FOO_MIN-1>& FooWrapper::initFooFnTable<FooWrapper::FOO_MAX>(std::array<FooWrapper::FooMakerFn*, FooWrapper::FOO_MAX-FooWrapper::FOO_MIN-1>& fnTable)
{
fnTable[FOO_MAX - FOO_MIN] = FooWrapper::fooMaker<FooWrapper::FOO_MAX>;
return fnTable;
}
这是完整的代码:
#include <memory>
#include <string>
#include <iostream>
/* Interface
*/
struct IFoo
{
virtual void lol(void) = 0;
};
/* Template Specialization
*/
template<std::size_t N>
class Foo : public IFoo
{
void lol(void)
{
std::cout << "Lol: " << N << std::endl;
}
};
/* Wrapper for the template
*/
class FooWrapper : public IFoo
{
std::unique_ptr<IFoo> mfoo;
public:
void setSize(std::size_t size)
{
if(size >= FOO_MIN && size <= FOO_MAX)
mfoo = fooFnTable[size - FOO_MIN]();
else
throw std::runtime_error(std::to_string(size) + " not supported.");
}
FooWrapper(std::size_t size)
{
this->setSize(size);
}
void lol(void)
{
mfoo->lol();
}
private:
template<unsigned i>
static std::unique_ptr<IFoo> fooMaker()
{
return std::make_unique< Foo<i> >();
}
static constexpr unsigned FOO_MIN = 1;
static constexpr unsigned FOO_MAX = 3;
using FooMakerFn = std::unique_ptr<IFoo>();
template<unsigned min>
static std::array<FooMakerFn*, FOO_MAX-FOO_MIN-1>& initFooFnTable(std::array<FooMakerFn*, FOO_MAX-FOO_MIN-1>& fnTable);
static std::array<FooMakerFn*, FOO_MAX-FOO_MIN-1> fooFnTable;
};
std::array<FooWrapper::FooMakerFn*, FooWrapper::FOO_MAX-FooWrapper::FOO_MIN-1> FooWrapper::fooFnTable = FooWrapper::initFooFnTable<FooWrapper::FOO_MIN>(FooWrapper::fooFnTable);
template<unsigned min>
std::array<FooWrapper::FooMakerFn*, FooWrapper::FOO_MAX-FooWrapper::FOO_MIN-1>& FooWrapper::initFooFnTable(std::array<FooWrapper::FooMakerFn*, FooWrapper::FOO_MAX-FOO_MIN-1>& fnTable)
{
fnTable[min - FOO_MIN] = FooWrapper::fooMaker<min>;
return initFooFnTable<min+1>(fnTable);
}
template<>
std::array<FooWrapper::FooMakerFn*, FooWrapper::FOO_MAX-FooWrapper::FOO_MIN-1>& FooWrapper::initFooFnTable<FooWrapper::FOO_MAX>(std::array<FooWrapper::FooMakerFn*, FooWrapper::FOO_MAX-FooWrapper::FOO_MIN-1>& fnTable)
{
fnTable[FOO_MAX - FOO_MIN] = FooWrapper::fooMaker<FooWrapper::FOO_MAX>;
return fnTable;
}
int main(void)
{
FooWrapper a(3u); // ok
a.setSize(2u); // ok
a.setSize(0u); // will throw an exception at runtime
a.lol();
return EXIT_SUCCESS;
}