我有一个template <bool P> class Foo
里面有很多代码。我希望能够将Foo<true>
转换为Foo<false>
,即有一个operator Foo<false>()
的方法。但是编译器不喜欢 Foo 存在的这种方法,它只喜欢 Foo<true>
的方法,并警告如何"不会调用运算符进行隐式或显式转换"(GCC 5.4.x)
我似乎不能使用 SFINAE 来做到这一点:std::enable_if
适用于类型; 我尝试过的值变体(真实案例有value
而不是type
成员)也没有帮助。
如何让此运算符仅针对Foo<false>
进行编译(除了专门Foo<false>
不同的运算符并复制我的所有代码)?
到目前为止,我最好的尝试是:
template <bool P> class Foo {
// etc. etc.
template <bool OtherValue>
operator Foo<OtherValue>()
{
static_assert(OtherValue, "You should not be using this conversion!");
// conversion code here
return Foo<false>(args,go,here);
}
}
如何让此运算符仅针对
Foo<false>
进行编译(除了专门Foo<false>
不同的运算符并复制我的所有代码)?
template <bool P>
struct Foo
{
template <bool P2 = P, typename = std::enable_if_t<P2 == true>>
operator Foo<false>()
{
return {};
}
};
使用 P2 = P
会将enable_if_t
的计算延迟到实际使用转换运算符的时间(而不是类实例化)。
如果我们试图简单地写:
template <typename = std::enable_if_t<P == true>>
operator Foo<false>()
{
return {};
}
std::enable_if_t<P == true>
将在Foo<P>
的实例化期间被计算,因为在实例化成员函数时没有发生替换。 替换在实例化Foo
时发生 - 因此 SFINAE 无法发生(因为尚未设置任何过载分辨率)。
通过添加bool P2 = P
默认参数,我们延迟了对转换运算符实例化的替换。这发生在过载解决期间,因此可以发生 SFINAE。
这个答案比我能解释得更好:https://stackoverflow.com/a/13401982/598696
你最好的尝试实际上已经不远了。您需要将转换运算符转换为模板,以便 SFINAE 可以工作。只需仅在P
为真的情况下强制执行它:
template<bool P>
struct foo {
template<bool V = P, std::enable_if_t<V>* = nullptr>
operator foo<false>() {
return {};
}
};
运算符是一个模板,其中所有参数都具有默认参数。所以它可以使用。但是,由于检查是V
,我们延迟对运算符的验证,直到过载解决。然后SFINAE消除它。
您可以使用帮助程序结构和规范来外部化运算符:
template <bool P> class Foo; // Forward declaration
template <bool P> struct FooConverterHelper {}; // False case: no conversion operator
template <> struct FooConverterHelper<true>
{
operator Foo<false>();
};
template <bool P> class Foo : public FooConverterHelper<P>
{
// Lot of stuff.
};
// Implementation of you conversion operator
FooConverterHelper<true>::operator Foo<false>()
{
//auto* that = static_cast<Foo<true>*>(this); // If needed
return Foo<false>{};
}
演示