【问题标题】:Conditionally enable constructor in C++ class [duplicate]有条件地在 C++ 类中启用构造函数 [重复]
【发布时间】:2018-05-28 07:28:48
【问题描述】:

我正在学习如何使用std::enable_if,到目前为止,我在有条件地启用和禁用我的课程中的方法方面取得了一定程度的成功。我将方法模板化为布尔值,并且此类方法的返回类型是此类布尔值的std::enable_if。这里的最小工作示例:

#include <array>
#include <iostream>
#include <type_traits>

struct input {};
struct output {};

template <class io> struct is_input { static constexpr bool value = false; };

template <> struct is_input<input> { static constexpr bool value = true; };

template <class float_t, class io, size_t n> class Base {
private:
  std::array<float_t, n> x_{};

public:
  Base() = default;
  Base(std::array<float_t, n> x) : x_(std::move(x)) {}
  template <class... T> Base(T... list) : x_{static_cast<float_t>(list)...} {}

  // Disable the getter if it is an input class
  template <bool b = !is_input<io>::value>
  typename std::enable_if<b>::type get(std::array<float_t, n> &x) {
    x = x_;
    }

  // Disable the setter if it is an output class
  template <bool b = is_input<io>::value>
  typename std::enable_if<b>::type set(const std::array<float_t, n> &x) {
    x_ = x;
    }
};

int main() {
  Base<double, input, 5> A{1, 2, 3, 4, 5};
  Base<double, output, 3> B{3, 9, 27};

  std::array<double, 5> a{5, 6, 7, 8, 9};
  std::array<double, 3> b{1, 1, 1};

  // A.get(a);   Getter disabled for input class
  A.set(a);

  B.get(b);
  // B.set(b);   Setter disabled for input class

  return 0;
}

但是,我不能应用此过程来有条件地启用 构造函数,因为它们没有返回类型。我已尝试针对 std::enable_if 的值进行模板化,但该类无法编译:

template <class io> class Base{
private:
  float_t x_;
public:
  template <class x = typename std::enable_if<std::is_equal<io,input>::value>::type> Base() : x_{5.55} {}
}

编译器错误如下:

In instantiation of ‘struct Base<output>’ -- no type named ‘type’ in  ‘struct std::enable_if<false, void>’

正如in this other post 所解释的,当一个类模板被实例化时,它会实例化它的所有成员声明(尽管不一定是它们的定义)。该构造函数的声明格式不正确,因此无法实例化该类。

您将如何规避此问题?我感谢任何帮助:)

编辑:

我想要以下内容:

struct positive{};
struct negative{};

template <class float_t, class io> class Base{
private:
  float_t x_;
public:
  template <class T = io, typename = typename std::enable_if<
                          std::is_same<T, positive>::value>::type>
  Base(x) : x_(x) {}

  template <class T = io, typename = typename std::enable_if<
                          std::is_same<T, negative>::value>::type>
  Base(x) : x_(-x) {}

如果可能的话。

【问题讨论】:

  • 投反对票的人能否解释一下他投反对票的原因?
  • 可能是因为简单的搜索找到了重复项。
  • 那么为什么不关闭重复呢?

标签: c++ constructor enable-if


【解决方案1】:

构造函数有两种方式,因为你不能在返回类型中使用它

默认模板参数:

template <class io> class Base
{
private:
    float_t x_;
public:
    template <class T = io,
              typename std::enable_if<std::is_equal<T, input>::value, int>::type = 0>
    Base() : x_{5.55} {}
};

默认参数:

template <class io> class Base{
private:
    float_t x_;
public:
    template <class T = io>
    Base(typename std::enable_if<std::is_equal<T, input>::value, int>::type = 0) :
        x_{5.55}
    {}
};

在您的情况下,您不能将 SFINAE 用作参数,仅取决于您的类参数,而不取决于函数的模板参数。

为:

template <class T = io, typename = typename std::enable_if<
                      std::is_same<T, positive>::value>::type>
Base(x) : x_(x) {}

template <class T = io, typename = typename std::enable_if<
                      std::is_same<T, negative>::value>::type>
Base(x) : x_(-x) {}

你犯了一个常见的错误:默认模板参数不是签名的一部分,所以你只声明和定义了两次

template <class, typename>
Base::Base(x);

这就是我使用的原因

typename std::enable_if<std::is_same<T, input>::value, int>::type = 0

其中类型在= 的左侧,因此您将有 2 个不同的类型,因此有 2 个不同的签名。

C++20 添加了requires,它允许简单地丢弃方法:

template <class float_t, class io> class Base{
private:
  float_t x_;
public:

  Base(x) requires(std::is_same<io, positive>::value) : x_(x) {}
  Base(x) requires(std::is_same<io, negative>::value) : x_(-x) {}

  // ...
};

【讨论】:

  • 我理解你指出的问题。如果构造函数不是针对类参数模板化的,而是针对它自己的参数,我们可以使用stackoverflow.com/questions/14603163/…。但这里不是这种情况。有什么办法吗?我已经编辑了我的问题以使其更清楚。谢谢您的回答! :)
  • 已编辑以在您的编辑中查明您的其他问题。
  • 这是关于默认参数和签名的一些非常有价值的见解(对我来说)!但是对于具有int 的解决方案,该方法不会为std::enable_if&lt;false,int&gt;::type 禁用。它仍然编译得很好。我现在在想,也许std::conditional 是我想要的,对吧?
  • std::enable_if&lt;false,int&gt;::type 是一个硬错误,std::enable_if&lt;cond&lt;T&gt;::value,int&gt;::typecond&lt;T&gt;::value 导致 false 将不允许重载。 std::conditional 似乎不是你想要的。
  • 你完全正确!我正在编译一个与我在此处发布的文件略有不同的文件,其中调用了不同的构造函数。是的,这正是我所需要的。谢谢!
猜你喜欢
  • 2011-07-18
  • 2013-05-22
  • 2017-07-19
  • 2015-01-20
  • 2018-08-28
  • 1970-01-01
  • 2020-09-22
  • 1970-01-01
相关资源
最近更新 更多