根据数值模板参数有条件地编译转换运算符



我有一个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>{};
}

演示

最新更新