基于类型特征专门化演员

时间:2017-10-14 17:10:34

标签: c++ casting template-meta-programming sfinae

这是我之前question的后续内容。

我有一个带有强制转换操作符的类。在预C ++ 17环境中,这会产生在执行初始化时无法选择适当的构造函数重载的错误。我想通过标记某些类型的强制转换运算符explicit来调整行为。但是,我找不到办法。

这是一个人为的例子:我想要一个隐式的转换操作符来表示整数类型,并且显式地显示所有其他类型。

这不起作用,因为我们无法确定具有U类型表达式的typename std::enable_if<!std::is_integral<U>::value, U>::type

struct C {
    template<typename U>
    operator typename std::enable_if< std::is_integral<U>::value, U>::type() const {
        return 1;
    }

    template<typename U>
    explicit operator typename std::enable_if<!std::is_integral<U>::value, U>::type() const {
        return 1.5;
    }
};

这个没有编译说C::operator U() cannot be overloaded

struct C {
    template<typename U, typename = typename std::enable_if< std::is_integral<U>::value, U>::type>
    operator U() const {
        return 1;
    }

    template<typename U, typename = typename std::enable_if<!std::is_integral<U>::value, U>::type>
    explicit operator U() const {
        return 1.5;
    }
};

我无法声明类template<typename U, typename = void> operator U();的函数并且部分特殊化它,因为不允许部分函数专门化并且使辅助类看起来对我来说太过分了。

如何根据我投射到的某些特征来声明强制转换操作符?

我需要一个C ++ 11解决方案,就像在C ++ 17中一样,上一个问题的问题已经是resolved。b

4 个答案:

答案 0 :(得分:2)

您可以将这些运算符的定义移动到基类。这种方法允许您对隐式和显式运算符设置约束:

#include <type_traits>
#include <iostream>

template<typename TDerived> class
t_ImplicitlyConvertableToAnything
{
    public: template
    <
        typename TTarget
    ,   typename TEnabled = typename ::std::enable_if_t<::std::is_integral<TTarget>::value>
    >
    operator TTarget(void) const
    {
        auto const & self{static_cast<const TDerived &>(*this)};
        return(self.template CheckedConversion_To_Integral<TTarget>());
    }
};

template<typename TDerived> class
t_ExplicitlyConvertableToAnything
{
    public: template
    <
        typename TTarget
    ,   typename TEnabled = typename ::std::enable_if_t<!::std::is_integral<TTarget>::value>
    > explicit
    operator TTarget(void) const
    {
        auto const & self{static_cast<const TDerived &>(*this)};
        return(self.template CheckedConversion_To_NonIntegral<TTarget>());
    }
};

class
t_ConvertableToAnything
:   public t_ImplicitlyConvertableToAnything<t_ConvertableToAnything>
,   public t_ExplicitlyConvertableToAnything<t_ConvertableToAnything>
{
    public: template<typename TTarget> decltype(auto)
    CheckedConversion_To_Integral(void) const
    {
        return(static_cast<TTarget>(1));
    }

    public: template<typename TTarget> decltype(auto)
    CheckedConversion_To_NonIntegral(void) const
    {
        return(static_cast<TTarget>(3.14));
    }
};


int main()
{
    t_ConvertableToAnything c;
    ::std::cout << ([](int x){return(x);})(c) << ::std::endl;
    ::std::cout << static_cast<float>(c) << ::std::endl;
    return(0);
}

Run this code online

答案 1 :(得分:1)

您可以使用非类型模板参数来避免“无法重载”问题:

#include <iostream>
#include <type_traits>

struct A { };
struct B { };

struct C {
    template <typename U,
              typename std::enable_if<std::is_integral<U>::value>::type* = nullptr>
    explicit operator U() const {
        return 1;
    }

    template<typename U,
     typename std::enable_if<std::is_same<U, A>::value>::type* = nullptr>
    explicit operator U() const {
        return A{ };
    }

     template<typename U,
     typename std::enable_if<std::is_same<U, B>::value>::type* = nullptr>
    explicit operator U() const {
        return B{ };
    }

};

int main() {
    C c;
    long y = static_cast<int>(c);
    B b = static_cast<B>(c);
    A a = static_cast<A>(c);
}

https://ideone.com/smfPwF

答案 2 :(得分:1)

您可以使用带有虚拟模板参数的技巧来重载您的演员操作符以消除歧义。

struct C {
    template<typename U, 
             typename = typename enable_if<is_integral<U>::value, U>::type, 
             int = 0> // <== hete
    operator U() const {
        return 1;
    }

    template<typename U, 
             typename = typename enable_if<!is_integral<U>::value, U>::type, 
             char = 0> //  <== and here
    explicit operator U() const {
        return 1.5;
    }
};

由于模板签名现在不同,因此没有歧义。

答案 3 :(得分:0)

试试这个。只需忽略显式运算符的约束,因为它涵盖了第一个运算符所没有的所有情况。

Coliru示例:http://coliru.stacked-crooked.com/a/3d0bc6e59ece55cf

#include <iostream>
#include <type_traits>

struct C {
    template <typename U,
              typename = typename std::enable_if< std::is_integral<U>::value>::type>
    operator U() const {
        return 1;
    }

    template<typename U, typename std::enable_if<!std::is_integral<U>::value>::type* = nullptr>
    explicit operator U() const {
        return 1.5;
    }
};

int main() {
    C c;
    int v = c;
    int w = c;
    int x = static_cast<int>(c);
    long y = static_cast<int>(c);
    double z = static_cast<double>(c);

    std::cout << v << std::endl;
    std::cout << w << std::endl;
    std::cout << x << std::endl;
    std::cout << y << std::endl;
    std::cout << z << std::endl;
}

感谢@Jodocus启用显式转换为整数类型。