【问题标题】:make a variadic constructor for signed and unsigned variables using enable_if使用 enable_if 为有符号和无符号变量创建可变参数构造函数
【发布时间】:2016-02-01 18:11:17
【问题描述】:

我想为一个类创建一个构造函数,使用任何整数类型,但要区分有符号和无符号。我不希望这成为类本身的模板。以下不起作用。 Visual Studio 只是说没有参数匹配。

class Thing{
public:
    template<typename Integral>
    Thing(
        typename std::enable_if<
            std::is_integral<Integral>::value &&
            !std::is_same<Integral,bool>::value &&
            std::is_signed<Integral>::value
            ,Integral
        >::type num
    ){
        //constructor using signed variable as input
    }
    template<typename Integral>
    Thing(
        typename std::enable_if<
            std::is_integral<Integral>::value &&
            !std::is_same<Integral,bool>::value &&
            !std::is_signed<Integral>::value//notice this is different
            ,Integral
        >::type num
    ){
        //constructor using unsigned variable as input
    }
};

【问题讨论】:

  • 它不工作?它在做什么? :)
  • 缺少public 关键字至少说明了我在尝试上面的代码时会遇到的第一个错误......

标签: c++ templates sfinae enable-if


【解决方案1】:

我们需要将 SFINAE 移动到模板中。如果我们使用

class Thing{
public:
    template<typename Integral, typename std::enable_if<
            std::is_integral<Integral>::value &&
            !std::is_same<Integral,bool>::value &&
            std::is_signed<Integral>::value
            ,Integral>::type* = nullptr> // will fail if type does not exist
    Thing(Integral i)
//        ^ use Integral type here
    {
        std::cout << "signed\n";
    }
    template<typename Integral, typename std::enable_if<
            std::is_integral<Integral>::value &&
            !std::is_same<Integral,bool>::value &&
            !std::is_signed<Integral>::value//notice this is different
            ,Integral>::type* = nullptr>
    Thing(Integral i)
    {
        std::cout << "unsigned\n";
    }
};

int main()
{
    int a = 10;
    Thing b(a);
    unsigned int c = 10;
    Thing d(c);
}

我们得到

signed
unsigned

Live Example

我还必须将构造函数设为public,因为它们默认为private

【讨论】:

    【解决方案2】:

    问题是该类型出现在non-deduced context 中,因此编译器无法从std::is_integral&lt;Integral&gt;::value 之类的内容中推断出它。试试这个:

    #include <iostream>
    #include <type_traits>
    
    class Thing{
    public:
        template<typename Integral>
        Thing(Integral num,
            typename std::enable_if<
                std::is_integral<Integral>::value &&
                !std::is_same<Integral,bool>::value &&
                std::is_signed<Integral>::value
                ,Integral
            >::type* = nullptr
        ){
            std::cout << "signed\n";
            //constructor using signed variable as input
        }
    
        template<typename Integral>
        Thing(Integral num,
            typename std::enable_if<
                std::is_integral<Integral>::value &&
                !std::is_same<Integral,bool>::value &&
                !std::is_signed<Integral>::value//notice this is different
                ,Integral
            >::type* = nullptr
        ){
            std::cout << "unsigned\n";
            //constructor using unsigned variable as input
        }
    };
    
    int main()
    {
        int x{};
        unsigned int y{};
        Thing thing1(x);
        Thing thing2(y);
    }
    

    Live on Coliru

    旁注:让你的构造函数public,否则你无法实例化你的对象。

    【讨论】:

    • 你偷偷地避免指出 OP 还需要制作 ctor public :-)
    • @AndyG 我确实忘了提及这一点,但在我的代码中将它们设为public ;)
    • 我个人更喜欢将enable_if 放在模板参数中:template&lt;typename T, typename std::enable_if&lt; (std::is_integral&lt;T&gt;::value) &amp;&amp; (!std::is_same&lt;T,bool&gt;::value) &amp;&amp; (std::is_signed&lt;T&gt;::value), int&gt;::type = 0&gt; Thing(T _in) 但都是一样的
    • @AndyG 我个人也更喜欢这个,但是当我写答案时,上面的解决方案需要最少的编辑,并且 Nathan 已经用另一种方法发布了一个答案,所以我会留下我的是。
    猜你喜欢
    • 2015-12-28
    • 1970-01-01
    • 2010-10-11
    • 2014-06-22
    • 1970-01-01
    • 1970-01-01
    • 2020-10-30
    • 2013-10-28
    • 1970-01-01
    相关资源
    最近更新 更多