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-当然,它可以访问。但在名称查找后会检查访问权限。内联好友的名称查找与成员函数的查找一样有效。但对于类外定义,您需要像任何自由函数一样进行限定。