7

Here is my implementation of converting binary literal to decimal:

template<char Head, char... Tail>
constexpr int operator"" _b()
{
    if constexpr (sizeof... (Tail) == 0)
    {
        return Head - '0';
    }
    else
    {
        return (Head - '0') * (1 << sizeof...(Tail)) + operator"" _b<Tail...>();
    }
}

GCC compiles happily,

while Clang fails:

prog.cc:1:2: error: template parameter list for literal operator must be either 'char...' or 'typename T, T...'
        template<char Head, char... Tail>
        ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
prog.cc:19:27: error: no matching literal operator for call to 'operator""_b' with argument of type 'unsigned long long' or 'const char *', and no matching literal operator template
    std::cout << 110110110_b;
                      ^

icc also fails:

error: a literal operator template must have a template parameter list equivalent to "<char ...>"

    constexpr int operator"" _b()

                  ^

MSVC also fails:

<source>(2): error C3686: 'operator ""_b': literal operator template must have exactly one template parameter that is a parameter pack

So, icc requires char... while clang and msvc require typename T, T... or char..., only gcc allow my Head and Tail.

The workaround should be simple ---- just replace char Head, char... Tail with char... digits and return a new aux function which using char Head, char... Tail as template parameters, or use a struct then specialize head and head, tail... without if constexpr.

But I didn't find related requirement from the standard draft. Can you tell me which one conforms the standard? Of course, if you have more elegant solution(besides the two I mentioned above) which will not invoke the compiler errors, please paste here, I'll very appreicate.

max66
  • 65,235
  • 10
  • 71
  • 111
Chen Li
  • 4,824
  • 3
  • 28
  • 55

3 Answers3

7

The standard spells it out pretty explicitly in [over.literal]/5:

The declaration of a literal operator template shall have an empty parameter-declaration-clause and its template-parameter-list shall have a single template-parameter that is a non-type template parameter pack with element type char.

So GCC is wrong in allowing this.

Nicol Bolas
  • 449,505
  • 63
  • 781
  • 982
3

I don't know who's right but I propose a C++17 alternative: comma operator and template folding instead of recursion

   template <char ... Chs>
   constexpr int operator"" _b()
    {
      int ret {};

      return ((ret <<= 1, ret += Chs - '0'), ...);
   }
max66
  • 65,235
  • 10
  • 71
  • 111
2

Literal operator template of the form

template <class T, T... >
constexpr int operator "" _b();

is a clang and gcc extension, MSVC don't support that extension.

There was however a proposal to reconsider literal operator templates

Jans
  • 11,064
  • 3
  • 37
  • 45
  • 2
    P0424 was abandoned for something much better: [P0732.](https://wg21.link/P0732) It just gives you the ability to make array objects that act like literal strings (among many other things). And it's already in the working paper for C++20. – Nicol Bolas Dec 15 '18 at 02:45