1

我正在尝试创建一个模板类来强制尺寸正确性(长度除以时间给出速度,等等)。

短篇小说: “无量纲”是可能的实例之一。如果我可以允许从双精度数显式构造所有实例化,并且进一步允许从双精度数隐式构造“无量纲”实例化(并且仅是无量纲实例化),那将会很方便。

长话短说:我的模板类布局为

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>是一个无量纲量,所以应该可以加减 aqty<0,0,0>和 double。我目前已通过声明来强制执行此操作

    qty operator+ (const double& rhs) const;

...但仅将其定义qty<0,0,0>. 这是可行的......但我认为我可以做得更好。如果我允许从 double 到 a 的隐式转换qty<0,0,0>,则添加一个 double 并且qty<0,0,0>不需要特殊处理。用户错误也会给出更多提示性的错误消息 --- 尝试将双倍添加到速度将表明转换是不可能的(理解维度不兼容的基本概念),而不是抱怨函数未定义(这可能会导致用户怀疑模板类中的错误)。

问题是我不能允许对模板参数的任何其他组合进行隐式构造。如果我这样做了,那么添加任何 qty 和 double 总是会成功;我想强迫用户考虑尺寸的正确性,并在添加之前将双精度常量显式转换为适当的尺寸(如果这是预期的操作)。但是,我确实希望允许从双精度数显式构造 --- 没有它,简单的声明

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仅删除一个实例化的规范,并且 --- 如果可能的话 --- 我不确定语法是什么。

4

2 回答 2

1

我们T根据 bool 创建一个类型或您无法创建的类型:

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 中,requires 子句可能会做得更好。

(标准的妄想症是因为标准中的措辞,其中模板方法必须具有至少一个有效的实例化:虽然无法访问,但operator T意味着您的代码使用的代码d将在 99% 的代码期望的上下文中工作double。)

于 2014-07-14T23:19:07.490 回答
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 转发给显式 ctor。

于 2014-07-14T21:43:37.850 回答