C++ 使用 enable_if 选择类构造函数

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/17842478/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 21:29:07  来源:igfitidea点击:

Select class constructor using enable_if

c++templatesconstructorsfinae

提问by tomas789

Consider following code:

考虑以下代码:

#include <iostream>
#include <type_traits>

template <typename T>
struct A {
    int val = 0;

    template <class = typename std::enable_if<T::value>::type>
    A(int n) : val(n) {};
    A(...) { }

    /* ... */
};

struct YES { constexpr static bool value = true; };
struct NO { constexpr static bool value = false; };

int main() {
    A<YES> y(10);
    A<NO> n;
    std::cout << "YES: " << y.val << std::endl
              << "NO:  " << n.val << std::endl;
}

I want to selectively define constructor A::A(int) only for some types using enable_if. For all other types there is default constructor A::A(...) which should be the default case for compiler when substitution fails. However this makes sense for me compiler (gcc version 4.9.0 20130714) is still complaining

我想有选择地定义构造函数 A::A(int) 仅用于使用 enable_if 的某些类型。对于所有其他类型,默认构造函数 A::A(...) 应该是替换失败时编译器的默认情况。然而,这对我来说很有意义,编译器(gcc version 4.9.0 20130714)仍然在抱怨

sfinae.cpp: In instantiation of 'struct A': sfinae.cpp:19:11:
required from here sfinae.cpp:9:5: error: no type named 'type' in
'struct std::enable_if'
A(int n) : val(n) {};

sfinae.cpp:在“struct A”的实例化中:sfinae.cpp:19:11:
从这里需要 sfinae.cpp:9:5: 错误:在
“struct std::enable_if”中没有名为“type”的类型
A(int n) : val(n) {};

Is something like this possible for constructor? Is this possible with another constructor(s) (copy-constructor and move-constructor)?

对于构造函数来说,这样的事情可能吗?这是否可以与另一个构造函数(复制构造函数和移动构造函数)一起使用?

采纳答案by jrok

I think this can't work with a single defaulted template parameter, because its value needs to be resolved when the class template is instantiated.

我认为这不能与单个默认模板参数一起使用,因为在实例化类模板时需要解析它的值。

We need to defer the substitution to the point of constructor template instantiation. One way is to default the template parameter to T and add an extra dummy parameter to the constructor:

我们需要将替换推迟到构造函数模板实例化点。一种方法是将模板参数默认为 T 并向构造函数添加一个额外的虚拟参数:

template<typename U = T>
A(int n, typename std::enable_if<U::value>::type* = 0) : val(n) { }

回答by Joel Falcou

Usually this is done using an anonymous defaulted argument :

通常这是使用匿名默认参数完成的:

A(int n, typename std::enable_if<T::value>::type* = 0) : val(n) {};
A(int n, typename std::enable_if<T::value>::type* = 0) : val(n) {};

You can not use template parameters from the class to SFINAE out methods. SO one way is to add a dummy type replacing int :

您不能使用来自类的模板参数到 SFINAE 输出方法。所以一种方法是添加一个虚拟类型替换 int :

see: http://ideone.com/2Gnyzj

见:http: //ideone.com/2Gnyzj

#include <iostream>
#include <type_traits>

template <typename T>
struct A {
    int val = 0;

    template<typename Integer
            ,typename  = typename std::enable_if<T::value && sizeof(Integer)>::type
            >
    A(Integer n) : val(n) {};

    A(...) {}
    /* ... */
};

struct YES { constexpr static bool value = true; };
struct NO { constexpr static bool value = false; };

int main() {
    A<YES> y(10);
    A<NO> n;
    std::cout << "YES: " << y.val << std::endl
              << "NO:  " << n.val << std::endl;
}

This works because you use a member template parameter to SFINAE out the constructor but the test is always true so it doesn't pollute your checks

这是有效的,因为您使用成员模板参数 SFINAE 出构造函数,但测试始终为真,因此它不会污染您的支票

回答by Amir Kirsh

With C++20

使用 C++20

You can achieve that simply by adding requiresto the template:

您只需添加requires到模板即可实现这一点:

template <typename U = T> requires U::value
A(int n) : val(n) { }

The requiresclause gets a constant expressionthat evaluates to trueor falsedeciding thus whether to consider this method in the overload resolution, if the requires clause is true, or ignore it otherwise.

如果 requires 子句为真,则该requires子句将constant expression计算为truefalse决定是否在重载决议中考虑此方法,否则忽略它。

Code: https://godbolt.org/z/CKTDFE

代码:https: //godbolt.org/z/CKTDFE