有时对于代数类型,使用构造函数使用文字值0
表示中性元素,或使用1
表示乘法恒等元素很方便,即使基础类型不是整数。
问题是,如何说服编译器仅接受0
或1
而不接受任何other整数并不明显。
在C ++ 14或更高版本中是否有办法做到这一点,例如结合文字,constexpr或static_assert?
让我用一个自由函数来说明(尽管这个想法是对采用单个参数的构造函数使用该技术。构造函数也不能采用模板参数)。
仅接受零的函数可以这样编写:
constexpr void f_zero(int zero){assert(zero==0); ...}
问题是,这只能在运行时失败。我可以写f_zero(2)
甚至f_zero(2.2)
,程序仍然可以编译。
第二种情况很容易删除,例如通过使用enable_if
template<class Int, typename = std::enable_if_t<std::is_same<Int, int>{}> >
constexpr void g_zero(Int zero){assert(zero==0);}
这仍然存在我可以传递任何整数的问题(并且它仅在调试模式下失败)。
在C ++ pre 11中,有能力做到这一点,只接受文字零。
struct zero_tag_{};
using zero_t = zero_tag_***;
constexpr void h_zero(zero_t zero){assert(zero==nullptr);}
这实际上允许在那里保留99%,但非常难看的错误消息除外。因为,基本上(模Maquevelian用法),唯一接受的参数是h_zero(0)
。
[这是事态在这里https://godbolt.org/z/wSD9ri所示。我看到了Boost.Units库中正在使用的这项技术。
1)现在可以使用C ++的新功能做得更好吗?
我问的原因是因为使用文字1
时上述技术完全失败。
2] 是否有等效的技巧可以应用于文字1
的情况?(理想情况下,作为单独的函数)。
我可以想象,可以发明一个非标准的长整型文字_c
,该文字创建std::integral_constant<int, 0>
或std::integral_constant<int, 1>
的实例,然后使函数采用这些类型。但是,对于0
情况,结果语法将最差。也许有些简单。
f(0_c);
f(1_c);
EDIT:我应该提到,由于f(0)
和f(1)
可能是完全独立的函数,因此理想情况下它们应该调用不同的函数(或重载)。
您可以通过将0或1作为模板参数来传递,如下所示:
template <int value, typename = std::enable_if_t<value == 0 | value == 1>>
void f() {
// Do something with value
}
然后将调用该函数,例如:f<0>()
。我不相信构造函数可以做同样的事情(因为您不能为构造函数显式设置模板参数),但是您可以将构造函数设为私有并具有静态包装函数,可以给模板参数执行检查:
class A {
private:
A(int value) { ... }
public:
template <int value, typename = std::enable_if_t<value == 0 || value == 1>>
static A make_A() {
return A(value);
}
};
A
类型的对象将用A::make_A<0>()
创建。