I'd like to create compile-time string literals with a custom layout.
Therefore I wrote this code (simplified):
#include <cstdint>
#include <type_traits>
#include <array>
template<
std::size_t Size,
typename CharType
>
struct string_literal
{
std::array<std::remove_const_t<CharType>, Size> chars;
constexpr string_literal(CharType(&literal_array)[Size]) :
chars(std::to_array<CharType, Size>(literal_array))
{
}
//causes an error with g++
virtual void Foo(){}
constexpr ~string_literal(){}
};
template <string_literal t>
constexpr auto* operator ""_s()
{
return &std::integral_constant<decltype(t), t>::value;
}
int main(){
auto x = u"Hello world"_s;
return 0;
}
It breaks on g++ when I add a virtual function so my question is: is that not allowed or is it g++-bug (it compiles with clang, msvc and intel-compiler)?
The actual error message is:
<source>: In function 'int main()':
<source>:32:14: error: no matching function for call to 'operator""_s<"H\000e\000l\000l\000o\000 \000w\000o\000r\000l\000d\000\000">()'
32 | auto x = u"Hello world"_s;
| ^~~~~~~~~~~~~~~~
<source>:32:14: note: there is 1 candidate
<source>:26:17: note: candidate 1: 'template<string_literal<...auto...> t> constexpr auto* operator""_s()'
26 | constexpr auto* operator ""_s()
| ^~~~~~~~
<source>:26:17: note: template argument deduction/substitution failed:
<source>:32:14: error: '((& string_literal<12, const char16_t>::_ZTV14string_literalILm12EKDsE) + 16)' is not a valid template argument for 'int (**)(...)' because it is not the address of a variable
32 | auto x = u"Hello world"_s;
| ^~~~~~~~~~~~~~~~
Here a more simplified version of the problem:
class Foo{
virtual void Bar(){
}
};
template<Foo foo>
void XXX(){
}
int main(){
constexpr static auto foo = Foo();
XXX<foo>();
return 0;
}
clang is correct here. The standard gives no limitation on whether literal types can or cannot have virtual members (basic.types/10.5):
A type is a literal type if it is:
...
- a possibly cv-qualified class type that has all of the following properties:
- it has a constexpr destructor,
- it is either a closure type, an aggregate type, or has at least one constexpr constructor or constructor template (possibly inherited from a base class) that is not a copy or move constructor,
- ...
- if it is not a union, all of its non-static data members and base classes are of non-volatile literal types.
nor it's required for NTTP (temp.param/7.3):
- A non-type template-parameter shall have one of the following (possibly cv-qualified) types:
- a structural type (see below), ...
...
- A structural type is one of the following:
- ...
- a literal class type with the following properties:
- all base classes and non-static data members are public and non-mutable and
- the types of all bases classes and non-static data members are structural types or (possibly multi-dimensional) array thereof.
Thus I see no reason for GCC to reject that code, as your class meets the given requirements