我有template <bool P> class Foo
,里面有很多代码。我希望能够将Foo<true>
转换为Foo<false>
,即拥有operator Foo<false>()
方法。但是编译器并不喜欢Foo存在的这种方法,它只对Foo<true>
喜欢它,并且警告如何不调用&#34;运算符进行隐式或显式转换&#34 ; (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);
}
}
答案 0 :(得分:5)
如何才能将此运算符仅针对
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
答案 1 :(得分:3)
你最好的尝试实际上并不遥远。您需要将转换运算符转换为模板,以便SFINAE可以工作。只是在案例P
为真的情况下强制执行:
template<bool P>
struct foo {
template<bool V = P, std::enable_if_t<V>* = nullptr>
operator foo<false>() {
return {};
}
};
运算符是一个模板,其中所有参数都具有默认参数。所以它可以使用。但是,由于检查在V
,我们会延迟验证操作员,直到超载解决。然后SFINAE消除了它。
答案 2 :(得分:1)
您可以使用辅助结构和specilization来外化您的运算符:
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>{};
}