I have the following code, which tries to convert a binary number (passed as a list of booleans, least-significant first, variable lenght) into a decimal number:
#include <iostream>
using namespace std;
template<typename T>
int bin_to_dec(int multi, T first) {
cout<<"mutli"<<multi<<endl;
return first?multi:0;
}
template<typename T, typename... Args>
int bin_to_dec(int multi, T first, Args... args) {
cout<<"mutli"<<multi<<endl;
return (first?multi:0) + adder(multi*2, args...);
}
template<typename T, typename... Args>
int bin_to_dec(T first, Args... args) {
cout<<"mutli"<<1<<endl;
return (first?1:0) + adder(2, args...);
}
int main()
{
cout<<bin_to_dec(true, true, false, true)<<endl;
}
It works quite well, but I would like to make it possible only for booleans, so when I try something like bin_to_dec(1,2,3) it should not compile. I was trying to use something like
template<bool First, bool... Bools>
but I can't figure out how to go further with that. Any ideas?
The obvious approach is to remove the function from the overload set for all template arguments but bool
:
template <typename... T>
std::enable_if_t<variadic_and(std::is_same<T, bool>::value...), int>
bin_to_dec(T... bits) {
// probably delegate to differently named functions as an implementation detail
// ...
}
variadic_and()
would be a constexpr
function returning true
if all its arguments are true
:
constexpr bool variadic_and() { return true; }
template <typename... T>
constexpr bool variadic_and(bool v, T... vs) {
return v && variadic_and(vs...);
}
With C++17 variadic_and()
would be necessary as parameter packs can be expanded with an operator. For example, the implementation of variadic_and()
could look like this:
template <typename... T>
constexpr bool variadic_and(T... vs) { return (vs && ...); }
The same approach could be used directly within std::enable_if_t<...>
.
Note : the approaches used above requires that the arguments are deduced as bool
, ie, they pretty much need to be of type bool
. Since the function shouldn't be callable with int
parameters and these would convert to bool
, testing whether the argument type is convertable to bool
doesn't seem appropriate. However, it may be reasonable to allow some conversions. If so, a corresponding trait would be used in the first paramter to std::enable_if_t
.
Just use a static assert. This works perfectly well:
int bin_to_dec() {
return 0;
}
template<typename T, typename ... Args>
int bin_to_dec(T first, Args ... rest)
{
static_assert(std::is_same<bool, T>::value, "Only valid for bools");
return (first ? 1 : 0) + (bin_to_dec(rest...) << 1);
}
int main()
{
cout<<bin_to_dec(true, true, false, true)<<endl;
cout<<bin_to_dec(1, 2, 3)<<endl; //compile error
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.