c++ - 如何防止模板化别名的隐式保值转换?

标签 c++ templates

我想为 double 的不同含义添加编译时检查.在现实世界中,我试图确保所有计算都以一致的单位进行。出于这个问题的目的,我编造了一个玩具示例,其中数字有味道。

我一直在尝试基于模板参数来实现这一点。使用 another answer 中描述的 c++0x 别名功能,我声明了一个 Number<Flavor>作为:

enum Flavor { Cherry, Plum, Raspberry };

template <Flavor> using Number = double;

这使我能够将局部变量或参数声明为特定类型的 Number,然后在大多数情况下将这些变量用作普通 double 。

我的问题是,我找不到一种方法来声明一个只接受特定风格作为其参数的函数:

void printCherryNumber(Number<Cherry> num) { cout << num << endl; }

int main() {
    Number<Cherry> a(5);
    Number<Plum> b(6);
    Number<Raspberry> c(3.1415);

    printCherryNumber(a);
    printCherryNumber(b);  // O, if only this could be a compiler error.

    return 0;
}

我的目标是制作 printCherryNumber(b)编译失败,因为 bNumber<Plum>不是Number<Cherry> .许多现有问题使用似乎不适用于我用于 Number 的类型别名构造的解决方案来解决此问题的变体。 .

我试过的东西

来自 this answer ,我看到了添加函数的模板版本的建议,该版本明确不执行任何操作或中断,如

template <typename T> void printCherryNumber(T num) = delete;

这根本没有效果,为什么会这样呢? Number<Plum>真的是doubleNumber<Cherry>也是double所以编译器永远不会为模板版本烦恼。

Another answer建议使用单个模板函数和静态断言,如:

template <Flavor F> void printPlumNumber(Number<F> num) {
    static_assert(F == Plum, "Wrong number flavor!");
    cout << num << endl;
}

这失败了,因为不管 F 的实际值如何, Number<F>仍然只是double所以我得到一个关于无法推断 F 值的错误.

别处有人suggests explicit specialization ,在这种情况下也失败了:

template <Flavor F> void printRaspberryNumber(Number<F> num) = delete;

template <> void printRaspberryNumber<Raspberry>(Number<Raspberry> num) {
    cout << num << endl;
}

在这里,编译器将调用视为不明确的,部分原因是它无法推断出 F 的值。 .

房间里的大象

我当然可以制作Number

形式的单值结构
template <Flavor> struct Number { double value; };

但我试图避免这个选项,因为我对拥有 .value 的想法并不十分兴奋。在我的代码中到处都是,我也不是特别渴望为 Number 定义运算符这只是代理到两倍。

强制性ideone

http://ideone.com/4HiYtI

最佳答案

这种方法的问题:

enum Flavor { Cherry, Plum, Raspberry };

template <Flavor> using Number = double;

是别名模板是透明的。 Number<Cherry> , Number<Plum> , 和 double都是同一类型。这根本无法解决您的问题。


您想要的通常称为不透明类型定义。你真的想要你的最后一个选择:

template <Flavor>
struct Number {
    double value;

    operator double() const { return value; } // for convenience
    Number& operator=(double ); // if necessary
    // possibly more operations
};

这边,Number<Cherry>Number<Plum>不同的类型。它们不能相互转换。和 double不能隐式转换为任何一个。


你也可以看看 BOOST_STRONG_TYPEDEF 及其实现,也是为了解决这个问题。

关于c++ - 如何防止模板化别名的隐式保值转换?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38649229/

相关文章:

c++ - 在 Ubuntu Linux 上使用 Kinect 编程

c++ - 模板区域中的不可推导上下文

c++ - 我的 hdc/hbitmap 的内存泄漏在哪里?

android - FFT 实现产生毛刺

c++ - 如何在 Swift 中使用泛型实现 "C++-ish template specialization"?

c++ - 通过智能指针和转换对基本模板参数进行模板推导

C++模板类型和模板类型

templates - Azure - 不允许 Arm 模板修改现有资源

c++ - LLDB 调试器 - 定义自定义类型显示

c++ - 使用 std::cin 连续输入字符串