我有一个模板类来帮助在编译时计算物理量。它使用额外的模板参数(std::ratio
)来确保像Length
这样的东西只能添加到Length
,或者Area
是Length
乘以Length
。
#include <ratio>
template <
typename Length = std::ratio<0>, // Meter
typename Mass = std::ratio<0>, // Kilogram
typename Time = std::ratio<0>, // Second
typename Current = std::ratio<0>, // Ampere
typename Temperature = std::ratio<0>, // Kelvin
typename Amount = std::ratio<0>, // Mole
typename Luminous = std::ratio<0> // Candela
>
class Quantity {
private:
double value;
public:
constexpr Quantity(double val) : value(val) {}
Quantity &operator+=(Quantity const &that) {
value += that.value;
return *this;
}
// ...
};
但有时我想转换回一个简单的double
,与其他东西的接口。
我可以为模板化类添加一个成员函数,它返回内部的double
,或者在需要double
时允许隐式(或显式)转换为double
。
constexpr double getValue() { return value; }
constexpr operator double() { return value; }
然而,我真的只希望这种隐式转换发生在"维度"的数量均为0(模板参数均为0)。
我可以只声明相同的成员函数,并且只定义我想要的专门化。但这仍然声明,对于我不希望允许转换的类型,存在转换(你应该先除以你想要的单位)。这使得我的编辑器告诉我它是好的,但它不会在编译时链接。
是否有一种方法可以仅在特定的特化上声明成员函数?
值得注意的是,我现在被困在c++ 14上,否则我认为if constexpr
可以工作…
不能,if constexpr
不能用于提供类方法的条件定义。if constexpr
属于某个方法或函数,因此需要在使用if constexpr
做任何事情之前声明它,并且您的目标是甚至不声明它。
没有办法直接为特定的特化或模板实例实例化类方法,但是有一种常见的方法非常接近:模拟重载解析失败。
下面是一个简化的例子:
#include <type_traits>
#include <iostream>
template<typename T>
struct life {
template<typename=
typename std::enable_if<std::is_same<T,int>::value>::type>
constexpr int answer()
{
return 42;
}
};
int main()
{
life<int> of_brian;
std::cout << of_brian.answer() << std::endl; // Shows 42
life<double> of_black_night;
std::cout << of_black_night.answer() << std::endl; // Error
return 0;
}
模板类只对其int
实例有效地实现answer()
。gcc
的错误消息,对于试图从不需要的模板实例调用它是:
错误:调用' life
::answer() '没有匹配的函数
和"this doesn't exist, pal"非常相似。
这在逻辑上与你试图对模板做的事情是等同的,唯一的区别是你需要检查一堆模板参数,而不是一个。