如何在尝试为某些非类型值实例化模板子类方法时产生编译器错误?
How do I produce a compiler error upon an attempt to instantiate a template subclass method for certain non-type values?
如果使用程序为某个模板参数调用非类型模板 class 方法,我想生成一个编译器错误。
typedef SubWithTemplate<1> SubWithTemplate1;
typedef SubWithTemplate<2> SubWithTemplate2;
SubWithTemplate1 &subWithTemplate1 = SubWithTemplate1::instance;
SubWithTemplate2 &subWithTemplate2 = SubWithTemplate2::instance;
subWithTemplate1.doSomething(); // Should compile OK
subWithTemplate1.doSomethingElse(); // Should compile OK
subWithTemplate2.doSomething(); // Should NOT compile OK
subWithTemplate2.doSomethingElse(); // Should compile OK
我的出发点是下面两个classes:
Super.h:
class Super {
protected:
Super() {}
public:
virtual void doSomething();
void doSomethingElse();
};
Super.cpp:
void Super::doSomething() {}
void Super::doSomethingElse() {}
SubWithTemplate.h:
template<int SUBNUMBER>
class SubWithTemplate : public Super {
public:
static SubWithTemplate<SUBNUMBER> instance;
void doSomething() {
// Do something
};
private:
SubWithTemplate() : Super() {}
};
template<int SUBNUMBER>
SubWithTemplate<SUBNUMBER> SubWithTemplate<SUBNUMBER>::instance;
我对 Boost 或 mpl 不是很流利,但我有一些模糊的感觉 BOOST_MPL_ASSERT 可以给我带来一些成功。但我无法理解其中的本质。
我试过类似的方法:
SubWithTemplate.h:
...
void doSomething() {
BOOST_MPL_ASSERT_MSG(<some test on SUBNUMBER being different from 2 and 7 and less than 25>, <what here?>, <what here?> )
};
...
我不希望 Super 被模板化,因为它应该是所有子classes 的相同实例化。
如果我能避免在 doSomething 上使用 virtual,那就更好了。
如果有比我更专业的人能帮助我,我将不胜感激。
不是很好的解决方案,但是...如果您可以使用 C++11,通过 SFINAE 禁用 doSomething()
怎么样?
在下面的示例中,doSomething()
对除 2
之外的所有 SUBNUMBER
值启用
#include <type_traits>
class Super
{
protected:
Super () {}
void doSomething () {}
public:
void doSomethingElse () {}
};
template <int SUBNUMBER>
class SubWithTemplate : public Super
{
public:
static SubWithTemplate<SUBNUMBER> instance;
template <int I = SUBNUMBER>
typename std::enable_if<I!=2>::type doSomething ()
{ Super::doSomething(); }
private:
SubWithTemplate () : Super() {}
};
template<int SUBNUMBER>
SubWithTemplate<SUBNUMBER> SubWithTemplate<SUBNUMBER>::instance;
typedef SubWithTemplate<1> SubWithTemplate1;
typedef SubWithTemplate<2> SubWithTemplate2;
int main()
{
SubWithTemplate1 &subWithTemplate1 = SubWithTemplate1::instance;
SubWithTemplate2 &subWithTemplate2 = SubWithTemplate2::instance;
subWithTemplate1.doSomething(); // OK
subWithTemplate1.doSomethingElse(); // OK
//subWithTemplate2.doSomething(); // compilation error
subWithTemplate2.doSomethingElse(); // OK
}
--- 编辑 ---
正如 Guillaume Racicot 所指出的(谢谢!)这个解决方案可以通过显式模板值来规避(I = SUBNUMBER
只是一个默认值)。
所以如果
subWithTemplate2.doSomething();
给出一个编译错误(按照OP的要求),
subWithTemplate2.doSomething<1>();
编译没有问题。
为避免这种情况,我可以提出几个解决方案。
(1) 您可以在函数体中添加一个 static_assert()
,以强制执行 I == SUBNUMBER
;像
template <int I = SUBNUMBER>
typename std::enable_if<I!=2>::type doSomething ()
{
static_assert(I == SUBNUMBER, "I != SUBNUMBER; this in wrong");
Super::doSomething();
}
(2) 按照 Guillaume Racicot 的建议(再次感谢!),您可以在 std::enable_if<>
测试中集成 I == SUBNUMBER
;像
template <int I = SUBNUMBER>
typename std::enable_if<(I!=2) && (I == SUBNUMBER)>::type
doSomething ()
{ Super::doSomething(); }
我发现第二种解决方案更优雅一些,但我不是专家,对我来说,这是一个品味问题。
--- 编辑 2 ---
how could I prevent the SubWithTemplate class from being instantiated unless the SUBNUMBER is within a given interval?
防爆满class?不仅是doSomething()
方法?
我想到的第一个方法是使用 static_alert()
。
举例来说,如果你想只允许[5,10[(包括5,排除10)范围内的SUBNUMBER
s,你可以这样写构造函数。
SubWithTemplate () : Super()
{ static_assert((SUBNUMBER >= 5) && (SUBNUMBER < 10), "error message"); }
但我想还有其他方法。
--- 编辑 3 ---
另一种防止 SubWithTemplate class 被实例化的方法,除非 SUBNUMBER 在给定的时间间隔内。
一种在 C++98 中也适用的方法。
它基于默认专业化和模板默认值。
class Super
{
protected:
Super () {}
void doSomething () {}
public:
void doSomethingElse () {}
};
template<bool b> struct boolWrapper {};
template <int I, bool = (I >= 0) && (I <= 20)>
struct rangeLimit;
template <int I>
struct rangeLimit<I, true>
{ };
template <int SUBNUMBER>
class SubWithTemplate : public Super, public rangeLimit<SUBNUMBER>
{
public:
static SubWithTemplate<SUBNUMBER> instance;
void doSomething ()
{ Super::doSomething(); }
private:
SubWithTemplate () : Super() {}
};
template<int SUBNUMBER>
SubWithTemplate<SUBNUMBER> SubWithTemplate<SUBNUMBER>::instance;
typedef SubWithTemplate<1> SubWithTemplate1;
typedef SubWithTemplate<2> SubWithTemplate2;
typedef SubWithTemplate<20> SubWithTemplate20;
//typedef SubWithTemplate<21> SubWithTemplate21; compilation error
int main()
{
}
如果使用程序为某个模板参数调用非类型模板 class 方法,我想生成一个编译器错误。
typedef SubWithTemplate<1> SubWithTemplate1;
typedef SubWithTemplate<2> SubWithTemplate2;
SubWithTemplate1 &subWithTemplate1 = SubWithTemplate1::instance;
SubWithTemplate2 &subWithTemplate2 = SubWithTemplate2::instance;
subWithTemplate1.doSomething(); // Should compile OK
subWithTemplate1.doSomethingElse(); // Should compile OK
subWithTemplate2.doSomething(); // Should NOT compile OK
subWithTemplate2.doSomethingElse(); // Should compile OK
我的出发点是下面两个classes:
Super.h:
class Super {
protected:
Super() {}
public:
virtual void doSomething();
void doSomethingElse();
};
Super.cpp:
void Super::doSomething() {}
void Super::doSomethingElse() {}
SubWithTemplate.h:
template<int SUBNUMBER>
class SubWithTemplate : public Super {
public:
static SubWithTemplate<SUBNUMBER> instance;
void doSomething() {
// Do something
};
private:
SubWithTemplate() : Super() {}
};
template<int SUBNUMBER>
SubWithTemplate<SUBNUMBER> SubWithTemplate<SUBNUMBER>::instance;
我对 Boost 或 mpl 不是很流利,但我有一些模糊的感觉 BOOST_MPL_ASSERT 可以给我带来一些成功。但我无法理解其中的本质。
我试过类似的方法:
SubWithTemplate.h:
...
void doSomething() {
BOOST_MPL_ASSERT_MSG(<some test on SUBNUMBER being different from 2 and 7 and less than 25>, <what here?>, <what here?> )
};
...
我不希望 Super 被模板化,因为它应该是所有子classes 的相同实例化。
如果我能避免在 doSomething 上使用 virtual,那就更好了。
如果有比我更专业的人能帮助我,我将不胜感激。
不是很好的解决方案,但是...如果您可以使用 C++11,通过 SFINAE 禁用 doSomething()
怎么样?
在下面的示例中,doSomething()
对除 2
SUBNUMBER
值启用
#include <type_traits>
class Super
{
protected:
Super () {}
void doSomething () {}
public:
void doSomethingElse () {}
};
template <int SUBNUMBER>
class SubWithTemplate : public Super
{
public:
static SubWithTemplate<SUBNUMBER> instance;
template <int I = SUBNUMBER>
typename std::enable_if<I!=2>::type doSomething ()
{ Super::doSomething(); }
private:
SubWithTemplate () : Super() {}
};
template<int SUBNUMBER>
SubWithTemplate<SUBNUMBER> SubWithTemplate<SUBNUMBER>::instance;
typedef SubWithTemplate<1> SubWithTemplate1;
typedef SubWithTemplate<2> SubWithTemplate2;
int main()
{
SubWithTemplate1 &subWithTemplate1 = SubWithTemplate1::instance;
SubWithTemplate2 &subWithTemplate2 = SubWithTemplate2::instance;
subWithTemplate1.doSomething(); // OK
subWithTemplate1.doSomethingElse(); // OK
//subWithTemplate2.doSomething(); // compilation error
subWithTemplate2.doSomethingElse(); // OK
}
--- 编辑 ---
正如 Guillaume Racicot 所指出的(谢谢!)这个解决方案可以通过显式模板值来规避(I = SUBNUMBER
只是一个默认值)。
所以如果
subWithTemplate2.doSomething();
给出一个编译错误(按照OP的要求),
subWithTemplate2.doSomething<1>();
编译没有问题。
为避免这种情况,我可以提出几个解决方案。
(1) 您可以在函数体中添加一个 static_assert()
,以强制执行 I == SUBNUMBER
;像
template <int I = SUBNUMBER>
typename std::enable_if<I!=2>::type doSomething ()
{
static_assert(I == SUBNUMBER, "I != SUBNUMBER; this in wrong");
Super::doSomething();
}
(2) 按照 Guillaume Racicot 的建议(再次感谢!),您可以在 std::enable_if<>
测试中集成 I == SUBNUMBER
;像
template <int I = SUBNUMBER>
typename std::enable_if<(I!=2) && (I == SUBNUMBER)>::type
doSomething ()
{ Super::doSomething(); }
我发现第二种解决方案更优雅一些,但我不是专家,对我来说,这是一个品味问题。
--- 编辑 2 ---
how could I prevent the SubWithTemplate class from being instantiated unless the SUBNUMBER is within a given interval?
防爆满class?不仅是doSomething()
方法?
我想到的第一个方法是使用 static_alert()
。
举例来说,如果你想只允许[5,10[(包括5,排除10)范围内的SUBNUMBER
s,你可以这样写构造函数。
SubWithTemplate () : Super()
{ static_assert((SUBNUMBER >= 5) && (SUBNUMBER < 10), "error message"); }
但我想还有其他方法。
--- 编辑 3 ---
另一种防止 SubWithTemplate class 被实例化的方法,除非 SUBNUMBER 在给定的时间间隔内。
一种在 C++98 中也适用的方法。
它基于默认专业化和模板默认值。
class Super
{
protected:
Super () {}
void doSomething () {}
public:
void doSomethingElse () {}
};
template<bool b> struct boolWrapper {};
template <int I, bool = (I >= 0) && (I <= 20)>
struct rangeLimit;
template <int I>
struct rangeLimit<I, true>
{ };
template <int SUBNUMBER>
class SubWithTemplate : public Super, public rangeLimit<SUBNUMBER>
{
public:
static SubWithTemplate<SUBNUMBER> instance;
void doSomething ()
{ Super::doSomething(); }
private:
SubWithTemplate () : Super() {}
};
template<int SUBNUMBER>
SubWithTemplate<SUBNUMBER> SubWithTemplate<SUBNUMBER>::instance;
typedef SubWithTemplate<1> SubWithTemplate1;
typedef SubWithTemplate<2> SubWithTemplate2;
typedef SubWithTemplate<20> SubWithTemplate20;
//typedef SubWithTemplate<21> SubWithTemplate21; compilation error
int main()
{
}