xnt*_*nth 5 c++ templates partial-specialization nested-class c++11
假设我有一个只对任何类型 T 执行加法的类。我想添加一个可选的范围检查(基于 bool 类型的模板参数),它将检查加法的结果是否属于给定的范围,或者否则它会抛出。这样做的一种方法是将类的所有基础知识包装在一个基类中,然后专门处理布尔模板参数。就像是:
// The base class; holds a starting value to add to and a maximum value
template<typename T>
class DummyImpl
{
private:
T mval, mmax;
public:
constexpr explicit DummyImpl(T x, T max_x) noexcept
: mval{x}, mmax{max_x}
{};
// base class; use a virtual destructor
virtual ~DummyImpl() {};
T max() const noexcept {return mmax;}
T val() const noexcept {return mval;}
};
// The "real" class; parameter B denotes if we want (or not)
// a range check
template<typename T, bool B>
class Dummy : DummyImpl<T> {};
// Specialize: we do want range check; if sum not in range
// throw.
template<typename T>
class Dummy<T, true> : DummyImpl<T>
{
public:
explicit Dummy(T x, T max_x) noexcept : DummyImpl<T>(x, max_x) {};
T add(T x) const noexcept( !true )
{
T ret_val = x + DummyImpl<T>::val();
if (ret_val < 0 || ret_val > DummyImpl<T>::max()) {
throw 1;
}
return ret_val;
}
};
// Specialize for no range check.
template<typename T>
class Dummy<T, false> : DummyImpl<T>
{
public:
explicit Dummy(T x, T max_x) noexcept : DummyImpl<T>(x, max_x) {};
T add(T x) const noexcept( !false )
{
return x + DummyImpl<T>::val();
}
};
Run Code Online (Sandbox Code Playgroud)
现在用户可以编写如下代码:
int main()
{
Dummy<float,false> d(0, 1000); //no range check; never throw
std::cout <<"\nAdding 156.7 gives " << d.add(156.7);
std::cout <<"\nAdding 3156.7 gives " << d.add(3156.7);
std::cout <<"\n";
return 0;
}
Run Code Online (Sandbox Code Playgroud)
有没有办法在不使用继承的情况下做到这一点?我认为使用嵌套类会更有效,但以下代码无法编译。
template<typename T, bool RC>
class Dummy
{
private:
T mval, mmax;
// parameter S is only used to enable partial specialization on
// parameter I
template<bool I, typename S> struct add_impl {};
template<typename S> struct add_impl<true, S>
{
T operator()(T x) const noexcept( !true )
{
T ret_val = x + mval;
if (ret_val < 0 || ret_val > mmax) {throw 1;}
return ret_val;
}
};
template<typename S> struct add_impl<false, S>
{
T operator()(T x) const noexcept( !false )
{
return x + mval_ref;
}
};
public:
constexpr explicit Dummy(T x, T max_x) noexcept
: mval{x}, mmax{max_x}
{};
void bar() const { std::cout << "\nin Base."; }
T max() const noexcept {return mmax;}
T val() const noexcept {return mval;}
T add(T x) const noexcept( !RC )
{
return add_impl<RC, T>()(x);
}
};
int main()
{
Dummy<float,false> d(0, 1000);
std::cout <<"\nAdding 156.7 gives " << d.add(156.7);
std::cout <<"\nAdding 3156.7 gives " << d.add(3156.7);
std::cout <<"\n";
return 0;
}
Run Code Online (Sandbox Code Playgroud)
它失败并显示错误消息(在 g++ 中):
error: invalid use of non-static data member ‘Dummy<float, false>::mval’
Run Code Online (Sandbox Code Playgroud)
有没有解决的办法?如果是这样,它是否比第一种解决方案更有效?嵌套类是否会为 Dummy 的任何实例增加大小?有没有更优雅的设计/实现?
我只会派遣RC。并使其成为一种类型:
template<typename T, bool RC>
class Dummy
{
private:
using do_range_check = std::integral_constant<bool, RC>;
T mval, mmax;
};
Run Code Online (Sandbox Code Playgroud)
接着就,随即:
T add(T x) const {
return add(x, do_range_check{});
}
private:
T add(T x, std::false_type /* range_check */) {
return x + mval;
}
T add(T x, std::true_type /* range_check */) {
T ret_val = x + mval;
if (ret_val < 0 || ret_val > mmax) {throw 1;}
return ret_val;
}
Run Code Online (Sandbox Code Playgroud)
优点是这是一个普通的成员函数 - 您不会卸载到需要将成员传递到的其他类型。而且你不需要专门化......任何东西。这太棒了。