假设我们有类似的东西:
template <class B>
class A
{
void Foo(B& b)
{
b.Bar(0.5);
}
};
class B
{
void Bar(float) {}
void Bar(double) {}
void Bar(int) {}
};
在此代码中,类型B
必须提供方法Bar()
,该方法采用某种整数类型的参数。问题在于此处允许B::Bar()
的所有3个版本。有没有办法只允许这些方法的一个版本,例如,只有在B
提供Bar(float)
时才编译?
答案 0 :(得分:1)
您可以使用这种(可怕的)技术,如果使用没有公共A
成员的类型B
实例化void Foo(float)
,则会导致编译失败从中获取特定的指针指向成员类型。
template <class B>
class A
{
public:
void Foo(B& b)
{
static_cast<void (B::*)(float)>(&B::Bar);
b.Bar(0.5);
}
};
(Demo of a resulting compilation failure。)
如果您想实际调用此方法,则需要使用b.Bar(0.5f);
。 0.5
是一个double
字面值,而不是float
字面值,因此您需要检查以确保它具有正确的成员,但如果它有void Bar(double)
,您会调用该字符无论如何。将常量更改为0.5f
可以解决此问题。
请注意,由于获取指针没有副作用且结果未被使用,任何体面的编译器都会将其作为无操作优化。
你也可以使用类似的东西去传统的SFINAE路线:
template <typename T, typename TMethod>
class has_bar_method
{
private:
struct yes { char _; };
struct no { char _[2]; };
template <typename U, TMethod = &U::Bar>
static yes impl(U*);
static no impl(...);
public:
enum { value = sizeof(impl(static_cast<T*>(nullptr))) == sizeof(yes) };
};
像这样使用:
void Foo(T& b)
{
static_assert(has_bar_method<T, void (T::*)(float)>::value,
"T has method void Bar(float)");
b.Bar(0.5f);
}
现在,如果模板无法实例化,我们会收到一条很好的消息,解释原因:
prog.cpp:25:8:错误:静态断言失败:T有方法void Bar(float)
(Demo)