Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Array to pointer class template argument deduction works for template guide, but not for non template version, is that correct or bug?

I have class template with single type param and const char* type full specialization, simplified example below:

template <typename T>
struct PrettyPrint {
    PrettyPrint(const T& value) : value(value) {}
    const T& value;
    friend std::ostream& operator << (std::ostream& os, const PrettyPrint& pp) {
        return os << "(" << pp.value << ")";
    }
};
template <>
struct PrettyPrint<const char*> {
    PrettyPrint(const char* value) : value(value) {}
    const char* value;
    friend std::ostream& operator << (std::ostream& os, const PrettyPrint& pp) {
        return os << "\"" << pp.value << "\"";
    }
};

In short - to print char strings like "abc" and all other values like (123) ("" vs ())

So, I added, as a replacement of additional partial specialization for all char[N] types a deduction guide:

template <std::size_t N>
PrettyPrint(char(&)[N]) -> PrettyPrint<const char*>; //deduction guide

Unfortunately it does not work:

 std::cout << PrettyPrint(7) << PrettyPrint("aaa") << PrettyPrint((const char*)"bbb");

(7)(aaa)"bbb"

Expected output:

(7)"aaa""bbb"

But, surprisingly, this works:

template <typename T, std::size_t N>
PrettyPrinter(T(&)[N]) -> PrettyPrinter<const T*>; //deduction guide

 std::cout << PrettyPrint(7) << PrettyPrint("aaa") << PrettyPrint((const char*)"bbb");

(7)"aaa""bbb"

So the questions:

  1. Is that correct (then why) or this is a bug in compilers (tested with gcc/clang - newest versions)
  2. If that is correct - then how to limit this template deduction guide to char only?
like image 453
PiotrNycz Avatar asked May 30 '18 14:05

PiotrNycz


2 Answers

This is expected. A string literal has type const char[N]. Note the const. A const value cannot bind to a non-const reference, so your deduction guide is effectively not chosen and the primary template gets instantiated instead.

template <std::size_t N>
PrettyPrint(const char(&)[N]) -> PrettyPrint<const char*>;

Your second deduction guide works because here, T is deduced to be const char, which is perfectly fine.

like image 104
Rakete1111 Avatar answered Oct 17 '22 15:10

Rakete1111


The issue here is a string literal is a const char[N], not a char[N]. Changing the guide to

template <std::size_t N>
PrettyPrint(const char(&)[N]) -> PrettyPrint<const char*>; //deduction guide

will give you the expected results.

like image 31
NathanOliver Avatar answered Oct 17 '22 16:10

NathanOliver