我正在尝试创建一个模板类来强制尺寸正确性(长度除以时间给出速度,等等)。
短篇小说:“Dimensionless”是可能的实例化之一。如果我可以允许从双精度显式构造所有实例化,并且允许从双精度隐式构造“无量纲”实例化(并且只有无量纲实例化),这将是方便的。
长篇故事:我的模板类格式为
template<int iLength, int iTime, int iMass>
class qty {
double data;
//Operators overloaded to enforce dimensional correctness
// e.g. qty<a,b,c> can only be added to qty<a,b,c>
// qty<a,b,c> * qty<a2,b2,c2> returns qty<a+a2,b+b2,c+c2>
};
遵循此样式,qty<0,0,0>
是无量纲数量,因此应该可以添加或减去qty<0,0,0>
和双精度数。我目前通过声明
qty operator+ (const double& rhs) const;
...但只有为qty<0,0,0>
定义它。这是可行的...但我认为我可以做得更好。如果我允许从double到qty<0,0,0>
的隐式转换,则添加double和qty<0,0,0>
将不需要特殊处理。用户错误也会提供更多暗示性错误消息 - 尝试向速度添加双精度表示转换不可能(获得维度不兼容的基本想法)而不是抱怨函数未定义(这可能会导致用户怀疑模板类中的错误。)
问题是我不能允许任何其他模板参数组合的隐式构造。如果我这样做,那么添加任何数量和双倍总是会成功;我想强迫用户考虑尺寸正确性,并在添加之前将双常量显式转换为适当的尺寸(如果这是预期的操作)。但是,我想从双打中允许显式构造---没有它,简单的声明
qty<1,-1,0> a(1.5); //speed with value 1.5
需要一个尴尬的转换功能
qty<1,-1,0> a = makeQty<1,-1,0>( 1.5 ); //my eyes hurt
这意味着我真正想要的是
template<int iLength, int iTime, int iMass>
class qty {
double data;
explicit qty(const double& rhs) : data(rhs) {} //general version prohibits
//implicit conversion
//...
};
template<>
qty<0,0,0>::qty(const double&rhs) : data(rhs) {} //Explicit instantiation
//for dimensionless case
// ... with black magic to reallow implicit conversion
// for this instantiation only ???
正如您所看到的,我不确定是否可以仅删除一个实例化的explicit
规范,并且---如果可能的话---我不确定语法是什么
答案 0 :(得分:1)
我们根据bool创建一个T
类型或无法创建的类型:
template<bool b, typename T>
struct block_unless {
struct type { type() = delete; operator T(); }; // operator T is standard-paranoia
};
template<typename T>
struct block_unless<true, T> {
using type = T;
};
template<bool b, typename T>
using block_unless_t = typename block_unless<b,T>::type;
template<bool b, typename T>
using block_if_t = block_unless_t<!b, T>;
然后我们保护我们想要使用其余代码内联阻止/激活的方法:
template<int a, int b, int c>
struct qty {
enum { scalar = (a==0)&&(b==0)&&(c==0) };
explict qty( block_if_t< scalar, double > d );
qty( block_unless_t< scalar, double > d );
};
那怎么样?
在C ++ 1y中,要求条款可能会做得更好。
(标准的偏执是因为标准中的verbage,模板方法必须至少有一个有效的实例化:虽然无法访问,operator T
意味着使用d
的代码可以在99%的代码需要double
的上下文。)
答案 1 :(得分:0)
您无法直接更改它,但以下内容适用于C ++ 11:
template<int iLength, int iTime, int iMass>
class qty_impl {
double data;
public:
explicit qty_impl(const double& rhs) : data(rhs) {} //general version prohibits
//implicit conversion
//...
};
// general case: simply forward to _impl
template<int iLength, int iTime, int iMass>
class qty : public qty_impl<iLength,iTime,iMass> {
// inherit ctors, including "explicit"
using qty_impl<iLength,iTime,iMass>::qty_impl;
};
// special case
template<>
class qty<0,0,0> : public qty_impl<0,0,0> {
using qty_impl<0,0,0>::qty_impl;
public:
// provide non-explicit ctor to override the inherited base ctors
qty(const double& rhs) : qty_impl<0,0,0>(rhs) {}
};
这使您可以保留几乎所有内容的通用实现,并简单地将非显式ctor转发给显式实现。