C++ 使用同一组参数分离内部和外部构造函数

C++ 使用同一组参数分离内部和外部构造函数,c++,c++11,c++14,C++,C++11,C++14,我有一个类型,它接受一个值,对照该类型的参数进行检查,从那时起,允许该值作为一个不变量进行检查。该类型还具有许多与之关联的操作,这些操作创建该类型的新值。所有这些操作都已定义,因此不需要进行检查。一旦用户的值在类型中,就不可能有该类型的无效值 我需要的是两个构造函数:一个内部构造函数和一个外部构造函数。外部构造函数应该执行检查,而内部构造函数不应该执行检查。否则,它们具有相同的参数,唯一的区别是检查,这是主要问题。出于性能原因,避免检查。下面是一个模拟的例子 #include <stdex

我有一个类型,它接受一个值,对照该类型的参数进行检查,从那时起,允许该值作为一个不变量进行检查。该类型还具有许多与之关联的操作,这些操作创建该类型的新值。所有这些操作都已定义,因此不需要进行检查。一旦用户的值在类型中,就不可能有该类型的无效值

我需要的是两个构造函数:一个内部构造函数和一个外部构造函数。外部构造函数应该执行检查,而内部构造函数不应该执行检查。否则,它们具有相同的参数,唯一的区别是检查,这是主要问题。出于性能原因,避免检查。下面是一个模拟的例子

#include <stdexcept>

template <int limit>
class ClippedValue;

template <int limit>
void check(ClippedValue<limit> v) {
    if (std::abs(v.value) > limit) {
        make_user_solve_P_eq_NP();
        throw std::range_error("Given value exceeds available range");
    }
}

template <int limit>
class ClippedValue {
public:  // external constructor
    constexpr ClippedValue(int a) : value(a) { check(*this); }
private:  // internal constructor
    constexpr ClippedValue(int a) : value(a) {}
public:  // members
    const int value;
public:  // friends
    template <int A, int B>
    friend constexpr ClippedValue<A + B> operator+ (ClippedValue<A> a, ClippedValue<B> b);
}

template <int A, int B>
constexpr ClippedValue<A + B> operator+ (ClippedValue<A> a, ClippedValue<B> b) {
    return a.value + b.value;
}

以上内容不可编译,两个构造函数是相同的。

正如您已经发现的,不能有两个具有相同接口的构造函数

您可以向第二个构造函数添加伪参数,以将其与第一个构造函数区分开来

template <int limit>
class ClippedValue
{
   public:

      // external constructor
      constexpr ClippedValue(int a) : value(a) { check(*this); }

   private:

      // A type that can be used only internally and by friends of the class.
      struct internal {};

      // internal constructor. An overload.
      // Use another argument, of type internal.
      constexpr ClippedValue(int a, internal) : value(a) {}

      ...
};

正如您已经发现的,不能有两个具有相同接口的构造函数

您可以向第二个构造函数添加伪参数,以将其与第一个构造函数区分开来

template <int limit>
class ClippedValue
{
   public:

      // external constructor
      constexpr ClippedValue(int a) : value(a) { check(*this); }

   private:

      // A type that can be used only internally and by friends of the class.
      struct internal {};

      // internal constructor. An overload.
      // Use another argument, of type internal.
      constexpr ClippedValue(int a, internal) : value(a) {}

      ...
};
上面的代码没有编译,这两个构造函数是相同的

的确如此。所以要区分它们

enum class unchecked_t {};
constexpr ClippedValue(unchecked_t, int a) : value(a) {}
标准库本身经常使用这种范式。它区分了重载,并且由于unchecked_t及其类型本身可以受访问控制,因此允许更细粒度的可访问性规范,例如密钥传递习惯用法

上面的代码没有编译,这两个构造函数是相同的

的确如此。所以要区分它们

enum class unchecked_t {};
constexpr ClippedValue(unchecked_t, int a) : value(a) {}

标准库本身经常使用这种范式。它区分了重载,并且由于unchecked_t及其类型本身可以受访问控制,因此允许更细粒度的可访问性规范,例如密钥传递习惯用法

让两个相同的函数做不同的事情是一个逻辑错误。您可能需要添加额外的伪参数或使用工厂函数。让两个相同的函数执行不同的操作是一个逻辑错误。您可能需要添加额外的伪参数或使用工厂函数。在这种情况下,您不需要显式调用类型构造函数吗?哪种方法需要在返回类型中再次键入相同的信息,或者使用decltype语句?或者有没有办法从friend函数返回未选中的\u t,value?@ktb-?它很容易返回{unchecked_t{},a.value+b.value};-在这种情况下,统一初始化不起作用。@ktb-无需等待。我忽略了一个事实,朋友不是内联定义的。您需要对它进行限定ClippedValue::unchecked{}这是否重要?它仍然是一个朋友,可以访问unchecked_t?@ktb-当然,它可以访问。但在名称查找后会检查访问权限。内联好友的名称查找与成员函数的查找一样有效。但对于类外定义,您需要像任何自由函数一样进行限定。在这种情况下,您不需要显式调用类型构造函数吗?哪种方法需要在返回类型中再次键入相同的信息,或者使用decltype语句?或者有没有办法从friend函数返回未选中的\u t,value?@ktb-?它很容易返回{unchecked_t{},a.value+b.value};-在这种情况下,统一初始化不起作用。@ktb-无需等待。我忽略了一个事实,朋友不是内联定义的。您需要对它进行限定ClippedValue::unchecked{}这是否重要?它仍然是一个朋友,可以访问unchecked_t?@ktb-当然,它可以访问。但在名称查找后会检查访问权限。内联好友的名称查找与成员函数的查找一样有效。但对于类外定义,您需要像任何自由函数一样进行限定。