如何将模板参数派生的编译时信息添加到模板中?

ste*_*fen 4 c++ templates c++11

我使用Stroustrup在GoingNative 2012(从23:00开始)提供的用户定义的文字来讨论单元实现.这是代码:

 #include <iostream>

 using std::cout;
 using std::endl;

 template<int M, int K, int S> 
 struct Unit { // a unit in the MKS system
   enum {m=M,kg=K,s=S}; 
 };

 template<typename Unit> // a magnitude with a unit
 struct Value {
   double val;
   constexpr Value(double d) : val(d) {}
 };

 using Meter = Unit<1,0,0>;
 using Second = Unit<0,0,1>;

 using Distance = Value< Meter >;
 using Time = Value< Second >;
 using Velocity = Value< Unit<1,0,-1> >;

 constexpr Value<Meter> operator "" _m(long double d)
 // a f-p literal with suffix 'm'
 {
   return Distance(d);
 }

 constexpr Value<Second> operator"" _s(long double d)
 // a f-p literal with suffix 's'
 {
   return Time(d);
 }

 constexpr Velocity operator/(Distance d, Time t)
 {
   return ( d.val / t.val );
 }

 int main(void)
 {
    Distance s = 100._m;
    Time t = 22._s;
    Velocity v = s/t;

    cout << "s " << s.val << "\nt " << t.val << endl;
    cout << "v " << v.val << endl;

   return 0;
 }
Run Code Online (Sandbox Code Playgroud)

如你所见,我可以自由地定义一个operator/来计算速度.输出是(需要gcc-4.7):

$ g++ -std=c++0x test_units_02.cc && ./a.out
s 100
t 22
v 4.54545
Run Code Online (Sandbox Code Playgroud)

到现在为止还挺好.现在我想将一个包含单位表示的字符串添加到struct Unit(或Value?).无论我想写什么方式

cout << "v " << v.val << v.unit << endl;
Run Code Online (Sandbox Code Playgroud)

得到类似的东西

v 4.54545 m^1 s^-1
Run Code Online (Sandbox Code Playgroud)

要么

v 4.54545 m^1 kg^0 s^-1
Run Code Online (Sandbox Code Playgroud)

它不需要美观,因为它只是用于检查.并学习如何做到这一点;).

当然,优雅的解决方案是在编译时对所有内容进行评估.

我有一些镜头,但我不会因为没有结果的尝试而感到困惑/迷惑......

eca*_*mur 6

首先我们添加一个unit成员Value:

 template<typename Unit> // a magnitude with a unit
 struct Value {
   double val;
   constexpr static Unit unit = {};
   constexpr Value(double d) : val(d) {}
 };
Run Code Online (Sandbox Code Playgroud)

然后我们写一个stream out运算符:

 template<int M, int K, int S>
 std::ostream &operator<<(std::ostream &os, Unit<M, K, S>) {
   return os << "m^" << M << " kg^" << K << " s^" << S;
 }
Run Code Online (Sandbox Code Playgroud)

在编译时生成字符串是可能的,但需要constexpr编译时字符串类(例如boost::mpl::string)和十进制格式 - 所有这些都是可行的,但在这种情况下并不特别值得.