编写仅接受文字“ 0”或文字“ 1”作为参数的函数

Sometimes for algebraic types it is convenient to have a constructor that takes a literal value 0 to denote the neutral element, or 1 to denote the multiplicative identity element, even if the underlying type is not an integer.

The problem is that it is not obvious how to convince the compiler only to accept, 0 or 1 without accepting any other integer.

有没有办法在C ++ 14或更高版本中做到这一点,例如结合文字,constexpr或static_assert?

让我用一个自由函数来说明(尽管这个想法是对带有单个参数的构造函数使用该技术)。

仅接受零的函数可以这样编写:

constexpr void f_zero(int zero){assert(zero==0); ...}

The problem is that, this could only fail at runtime. I could write f_zero(2) or even f_zero(2.2) and the program will still compile.

The second case is easy to remove, by using enable_if for example

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);}

This actually allowed one to be 99% there, except for very ugly error messages. Because, basically (modulo Maquevelian use), the only argument accepted would be h_zero(0).

This is situation of affairs is illustrated here https://godbolt.org/z/wSD9ri . I saw this technique being used in the Boost.Units library.

1)现在可以使用C ++的新功能做得更好吗?

The reason I ask is because with the literal 1 the above technique fails completely.

2) Is there an equivalent trick that can be applied to the literal 1 case?

I could imagine that one can invent a non-standard long long literal _c that creates an instance of std::integral_constant<int, 0> or std::integral_constant<int, 1> and then make the function take these types. However the resulting syntax will be worst for the 0 case. Perhaps there is something simpler.

f(0_c);
f(1_c);