以下代码显示了我使用的设计。我创建了一个封装模板类的包装类。包装器的方法允许使用开关选择我想要的专业化:
#include <memory>
#include <string>
/* Interface
*/
struct IFoo
{
virtual void lol(void) = 0;
};
/* Template Specialization
*/
template<std::size_t N>
class Foo : public IFoo
{
void lol(void) {}
};
/* Wrapper for the template
*/
class FooWrapper : public IFoo
{
std::unique_ptr<IFoo> mfoo;
public:
void setSize(std::size_t size)
{
switch (size) // how to 'simulate' this switch comportement
// with min/max constexpr variables ?
{
case 1u:
mfoo = std::make_unique< Foo<1u> >();
break ;
case 2u:
mfoo = std::make_unique< Foo<2u> >();
break ;
case 3u:
mfoo = std::make_unique< Foo<3u> >();
break ;
default:
throw std::runtime_error(std::to_string(size) + " not supported.");
}
}
FooWrapper(std::size_t size)
{
this->setSize(size);
}
void lol(void)
{
mfoo->lol();
}
};
int main(void)
{
FooWrapper a(3u); // ok
a.setSize(2u); // ok
a.setSize(0u); // will throw an exception at runtime
return EXIT_SUCCESS;
}
是否可以使用相同的比例,但使用最小和最大constexpr值,以及在范围内循环并为每个值执行良好模板的交换机的自动版本?
编辑:我正在搜索运行时解决方案,因为用户必须通过GUI选择setSize的参数。
答案 0 :(得分:3)
与所有模板元编程问题一样,涉及index_sequence
。在这种情况下,为index_sequence
上的模板参数建立一个Foo
的值,并迭代它们。为简单起见,这里的版本使用0
作为最小值,4
作为最大值:
template <std::size_t... Is>
std::unique_ptr<IFoo> create(std::size_t N, std::index_sequence<Is...> ) {
std::unique_ptr<IFoo> mfoo;
using swallow = int[];
(void)swallow{0,
(void(N == Is ? mfoo = std::make_unique<Foo<Is>>() : mfoo), 0)...
};
return mfoo;
}
std::unique_ptr<IFoo> create(std::size_t N) {
return create(N, std::make_index_sequence<4>{} );
}
create(N)
会为您提供Foo<N>
(如果0 <= N < 4
)或未设置unique_ptr
。如果它什么都不给你,你可以扔掉:
void setSize(std::size_t size) {
auto new_foo = create(size); // or call with index_sequence
if (!new_foo) {
// throw
}
mfoo = std::move(new_foo);
}
我将生成index_sequence<1, 2, 3>
作为练习。
答案 1 :(得分:1)
您可以创建一个init-time函数表,这样该表的每个成员都对应于上面的一个case语句。然后setSize
可以使用此表。通过使用constexpr
min和max参数,您可以使用模板特化指定此表的边界,并使用创建Foo对象的'maker'函数的模板实例填充它。
这是函数表代码的声明(全部在FooWrapper的私有部分中):
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;
}
这是完整的代码:
#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;
}
答案 2 :(得分:0)
我怀疑这是可能的。 setSize
可以constexpr
,因为它是具有非平凡析构函数的类的非静态成员。
因为无法创建constexpr
,所以代码中的所有模板参数都必须进行硬编码。