有条件地编译基于数字模板参数的转换运算符

时间:2017-10-24 09:52:40

标签: c++ class templates typecast-operator

我有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);
    }
}

3 个答案:

答案 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 = Penable_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>{};
}

Demo