简体   繁体   中英

How to specialize template pack?

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM