Disallow a specific function template instantiation - c++

I would like to define a template function but disallow instantiation with a particular type. Note that in general all types are allowed and the generic template works, I just want to disallow using a few specific types.
For example, in the code below I wish to prevent using double with the template. This doesn't actually prevent the instantiation, but just causes a linker error by not having the function defined.
template<typename T>
T convert( char const * in )
{ return T(); }
//this way creates a linker error
template<>
double convert<double>( char const * in );
int main()
{
char const * str = "1234";
int a = convert<int>( str );
double b = convert<double>( str );
}
The code is just a demonstration, obviously the convert function must do something more.
Question: In the above code how can I produce a compiler error when trying to use the convert<double> instantiation?
The closest related question I can find is How to intentionally cause a compile-time error on template instantiation It deals with a class, not a function.
The reason I need to do this is because the types I wish to block will actually compile and do something with the generic version. That's however not supposed to be part of the contract of the function and may not be supported on all platforms/compilers and in future versions. Thus I'd like to prevent using it at all.

I would use a static assert within your function call to create the proper failure during function instantiation:
template<typename T>
class is_double{ static const int value = false; }
template<>
class is_double<double>{ static const int value = true; }
template<typename T>
T convert( const char *argument ){
BOOST_STATIC_ASSERT( !is_double<T>::value );
//rest of code
}
And that should work within a function.

If you don't want to rely on static_assert or make the code portable pre-C++0x, use this:
template<class T>
void func(){
typedef char ERROR_in_the_matrix[std::is_same<T,double>::value? -1 : 1];
}
int main(){
func<int>(); // no error
func<double>(); // error: negative subscript
}

You could use a functor instead of a function:
template<typename T>
struct convert {
T operator()(char const * in) const { return T(); }
};
template<> struct convert<double>;
int main()
{
char const * str = "1234";
int a = convert<int>()( str );
double b = convert<double>()( str ); // error in this line
return 0;
}
This will give you an error at the point of instantiation.
By adding helper function you will get the wanted behaviour:
template<typename T>
struct convert_helper {
T operator()(char const * in) const { return T(); }
};
template<> struct convert_helper<double>;
template<typename T>
T convert( char const * in ) { return convert_helper<T>()( in ); }
int main()
{
char const * str = "1234";
int a = convert<int>( str );
double b = convert<double>( str );
return 0;
}

Consider Boost disable_if and Boost TypeTraits
Take a look at How can I write a function template for all types with a particular type trait?
This is an example:
#include <boost/type_traits.hpp>
#include <boost/utility/enable_if.hpp>
template<typename T>
T convert( char const * in,
typename boost::disable_if<boost::is_floating_point<T>, T>::type* = 0 )
{ return T(); }
int main()
{
char const * str = "1234";
int a = convert<int>( str );
double b = convert<double>( str );
return 0;
}
This is the compilation error for the string
double b = convert<double>( str );
1>.\simple_no_stlport.cpp(14) : error
C2770: invalid explicit template
argument(s) for 'T convert(const char
*,boost::disable_if,T>::type
*)' 1> .\simple_no_stlport.cpp(5) : see
declaration of 'convert'

Related

Deduce Function Arguments From A Function Type Declare, For Templated Struct Method?

I was wondering if it was possible to deduce the return type, and parameters from a function type define.
I was hoping to do something similar:
template<class T>
struct _function_wrapper_t
{
[return of T] call([Args of T]....)
{
return (T)m_pfnFunc(Args);
}
void* m_pfnFunc;
};
int MultiplyTwoNumbers(int nNum, int nNum2)
{
return nNum * nNum2;
}
int MultiplyThreeNumbers(int nNum, int nNum2, int* pnNum3)
{
return nNum * nNum2 * *pnNum3;
}
int main()
{
_function_wrapper_t<decltype(&MultiplyTwoNumbers)> two(&MultiplyTwoNumbers);
_function_wrapper_t<decltype(&MultiplyThreeNumbers)> three(&MultiplyThreeNumbers);
auto ret1 = two.call(1, 2);
auto ret2 = three.call(4, 5, 8);
}
However I'm not sure if its possible to discern the return type and function arguments from a type of function pointer.
if you did say
typedef void*(__cdecl* fnOurFunc_t)(const char*, int, float**);
The compiler knows to use that as the type in the future, does the same apply further to templates? This is needed for a VERY specific use case.
Thanks in advance!
The simple solution is to let the compiler deduce return type and let the caller pass the right types (and fail to compile when they don't):
template<class T>
struct _function_wrapper_t
{
template <typename ...U>
auto call(U&&... t)
{
return m_pfnFunc(std::forward<U>(t)...);
}
T m_pfnFunc;
};
If you do not like that you can use partial specialization:
template<class T>
struct _function_wrapper_t;
template <typename R,typename...Args>
struct _function_wrapper_t<R(*)(Args...)>
{
R call(Args...args)
{
return m_pfnFunc(args...);
}
using f_type = R(*)(Args...);
f_type m_pfnFunc;
};
Live Demo
PS: perfect forwarding is also possible in the latter case but it requires some boilerplate that I left out for the sake of brevity.
Check the std::function implementation. It seems it does what you need:
#include <functional>
int MultiplyTwoNumbers(int nNum, int nNum2)
{
return nNum * nNum2;
}
int MultiplyThreeNumbers(int nNum, int nNum2, int pnNum3)
{
return nNum * nNum2 * pnNum3;
}
int main()
{
std::function<decltype(MultiplyTwoNumbers)> two = &MultiplyTwoNumbers;
std::function<decltype(MultiplyThreeNumbers)> three = &MultiplyThreeNumbers;
auto ret1 = two(1, 2);
auto ret2 = three(4, 5, 8);
}

How to prevent usage of object in ellipsis

Is there a way to prevent the pass an object to an ellipsis?
Example:
The ellipsis is used in the following function
int my_printf( const char * format, ... );
And there is an object of some type:
struct Text
{
const char * c_str();
};
Text text;
Is it possible to change struct Text so that the following does not compile?
my_printf("%s", text ); // should fail to compile
my_printf("%s", text.c_str() ); // this was the intention
Changing my_printf to use variadic template arguments instead of an ellipsis is not an option.
Use a static assert:
#include <type_traits>
// test all parameters for being true
template<typename ... Args>
constexpr bool all(Args ... args) {
return (... && args);
}
// test if it's a class, error message has the name of the class
template<typename T>
struct not_an_object {
static const bool value = !std::is_class<T>::value;
static_assert(value, "no classes please");
};
// won't compile if there's a class object in the parameters
template<typename ... Ts, typename =
std::enable_if_t<all(not_an_object<Ts>::value ...)>>
void a_print(char const*fmt, Ts ... e){
my_printf(fmt, e...);
}
In case deleting the copy constructor is an option the usage in ellipsis results in an error.
Unfortunately declaring the copy constructor as explicit does not result in an error.
#include "stdio.h"
struct A
{
A( const A & ) = delete;
//explicit A( const A & ) = default;
A() {}
int m = 3;
};
int main ()
{
A a;
printf("%d", a); // error
}

c++: using constexpr to XOR data doesn't work

Here is my code:
template<int... I>
class MetaString1
{
public:
constexpr MetaString1(constexpr char* str)
: buffer_{ encrypt(str[I])... } { }
const char* decrypt()
{
for (int i = 0; i < sizeof...(I); ++i)
buffer_[i] = decrypt1(buffer_[i]);
buffer_[sizeof...(I)] = 0;
return buffer_;
}
private:
constexpr char encrypt(constexpr char c) const { return c ^ 0x55; }
constexpr char decrypt1(constexpr char c) const { return encrypt(c); }
private:
char buffer_[sizeof...(I)+1];
};
#define OBFUSCATED1(str) (MetaString1<0, 1, 2, 3, 4, 5>(str).decrypt())
int main()
{
constexpr char *var = OBFUSCATED1("Post Malone");
std::cout << var << std::endl;
return 1;
}
This is the code from the paper that I'm reading Here. The Idea is simple, to XOR the argument of OBFUSCATED1 and then decrypt back to original value.
The problem that I'm having is that VS 2017 gives me error saying function call must have a constant value in constant expression.
If I only leave OBFUSCATED1("Post Malone");, I have no errors and program is run, but I've noticed that if I have breakpoints in constexpr MetaString1 constructor, the breakpoint is hit, which means that constexpr is not evaluated during compile time. As I understand it's because I don't "force" compiler to evaluate it during compilation by assigning the result to a constexpr variable.
So I have two questions:
Why do I have error function call must have a constant value in constant expression?
Why do people use template classes when they use constexpr functions? As I know template classes get evaluated during compilation, so using template class with constexpr is just a way to push compiler to evaluate those functions during compilation?
You try to assign a non constexpr type to a constexpr type variable,
what's not possible
constexpr char *var = OBFUSCATED1("Post Malone")
// ^^^ ^^^^^^^^^^^
// type of var is constexpr, return type of OBFUSCATED1 is const char*
The constexpr keyword was introduced in C++11, so before you had this keyword you had to write complicated TMP stuff to make the compiler do stuff at compile time. Since TMP is turing complete you theoretically don't need something more than TMP, but since TMP is slow to compile and ugly to ready, you are able to use constexpr to express things you want evaluate at compile time in a more readable way. Although there is no correlation between TMP and constexpr, what means, you are free to use constexpr without template classes.
To achieve what you want, you could save both versions of the string:
template <class T>
constexpr T encrypt(T l, T r)
{
return l ^ r;
}
template <std::size_t S, class U>
struct in;
template <std::size_t S, std::size_t... I>
struct in<S, std::index_sequence<I...>>
{
constexpr in(const char str[S])
: str_{str[I]...}
, enc_{encrypt(str[I], char{0x12})...}
{}
constexpr const char* dec() const
{
return str_;
}
constexpr const char* enc() const
{
return enc_;
}
protected:
char str_[S];
char enc_[S];
};
template <std::size_t S>
class MetaString1
: public in<S, std::make_index_sequence<S - 1>>
{
public:
using base1_t = in<S, std::make_index_sequence<S - 1>>;
using base1_t::base1_t;
constexpr MetaString1(const char str[S])
: base1_t{str}
{}
};
And use it like this:
int main()
{
constexpr char str[] = "asdffasegeasf";
constexpr MetaString1<sizeof(str)> enc{str};
std::cout << enc.dec() << std::endl;
std::cout << enc.enc() << std::endl;
}

Initializing a static char based on template parameter

I want to do something like this :
template<typename T>
const char * toStr(T num)
{
thread_local static char rc[someval*sizeof(T)] str = "0x000...\0"; // num of zeros depends on size of T
// do something with str
return str;
}
I'm guessing there's some template metaprogramming I'd have to do but I'm not sure where to start.
Edit:
I found a related question here: How to concatenate a const char* in compile time
But I don't want the dependency on boost.
Not sure to understand what do you want but... if you want that the str initial value is created compile time and if you accept that toStr() call and helper function (toStrH() in the following example) a C++14 example follows
#include <utility>
template <typename T, std::size_t ... I>
const char * toStrH (T const & num, std::index_sequence<I...> const &)
{
static char str[3U+sizeof...(I)] { '0', 'x', ((void)I, '0')..., '\0' };
// do someting with num
return str;
}
template <typename T>
const char * toStr (T const & num)
{ return toStrH(num, std::make_index_sequence<(sizeof(T)<<1U)>{}); }
int main()
{
toStr(123);
}
If you need a C++11 solution, substitute std::make_index_sequence() and std::index_sequence isn't difficult.

Passing a string literal as a type argument to a class template

I want to declare a class template in which one of the template parameters takes a string literal, e.g. my_class<"string">.
Can anyone give me some compilable code which declares a simple class template as described?
Note: The previous wording of this question was rather ambiguous as to what the asker was actually trying to accomplish, and should probably have been closed as insufficiently clear. However, since then this question became multiple times referred-to as the canonical ‘string literal type parameter’ question. As such, it has been re-worded to agree with that premise.
You can have a const char* non-type template parameter, and pass it a const char[] variable with static linkage, which is not all that far from passing a string literal directly.
#include <iostream>
template<const char *str>
struct cts {
void p() {std::cout << str;}
};
static const char teststr[] = "Hello world!";
int main() {
cts<teststr> o;
o.p();
}
http://coliru.stacked-crooked.com/a/64cd254136dd0272
Further from Neil's answer: one way to using strings with templates as you want is to define a traits class and define the string as a trait of the type.
#include <iostream>
template <class T>
struct MyTypeTraits
{
static const char* name;
};
template <class T>
const char* MyTypeTraits<T>::name = "Hello";
template <>
struct MyTypeTraits<int>
{
static const char* name;
};
const char* MyTypeTraits<int>::name = "Hello int";
template <class T>
class MyTemplateClass
{
public:
void print() {
std::cout << "My name is: " << MyTypeTraits<T>::name << std::endl;
}
};
int main()
{
MyTemplateClass<int>().print();
MyTemplateClass<char>().print();
}
prints
My name is: Hello int
My name is: Hello
C++20 fixed_string + "Class Types in Non-Type Template Parameters"
Apparently, a proposal for this was first accepted, but then removed: "String literals as non-type template parameters"
The removal was partly because it was deemed to be easy enough to do with another proposal that was accepted: "Class Types in Non-Type Template Parameters".
The accepted proposal contains an example with the following syntax:
template <std::basic_fixed_string Str>
struct A {};
using hello_A = A<"hello">;
I'll try to update this with an example that actually tells me anything once I see a compiler that supports it.
A Redditor has also shown that the following compiles on GCC master, provided you define your own version of basic_fixed_string which was not in the standard library yet: https://godbolt.org/z/L0J2K2
template<unsigned N>
struct FixedString {
char buf[N + 1]{};
constexpr FixedString(char const* s) {
for (unsigned i = 0; i != N; ++i) buf[i] = s[i];
}
constexpr operator char const*() const { return buf; }
};
template<unsigned N> FixedString(char const (&)[N]) -> FixedString<N - 1>;
template<FixedString T>
class Foo {
static constexpr char const* Name = T;
public:
void hello() const;
};
int main() {
Foo<"Hello!"> foo;
foo.hello();
}
g++ -std=c++2a 9.2.1 from the Ubuntu PPA fails to compile that with:
/tmp/ccZPAqRi.o: In function `main':
main.cpp:(.text+0x1f): undefined reference to `_ZNK3FooIXtl11FixedStringILj6EEtlA7_cLc72ELc101ELc108ELc108ELc111ELc33EEEEE5helloEv'
collect2: error: ld returned 1 exit status
Bibliography: https://botondballo.wordpress.com/2018/03/28/trip-report-c-standards-meeting-in-jacksonville-march-2018/
Finally, EWG decided to pull the previously-approved proposal to allow string literals in non-type template parameters, because the more general facility to allow class types in non-type template parameters (which was just approved) is a good enough replacement. (This is a change from the last meeting, when it seemed like we would want both.) The main difference is that you now have to wrap your character array into a struct (think fixed_string or similar), and use that as your template parameter type. (The user-defined literal part of P0424 is still going forward, with a corresponding adjustment to the allowed template parameter types.)
This will be especially cool with the C++17 if constexpr: if / else at compile time in C++?
This kind of feature appears to be in line with the awesome "constexpr everything" proposals that went into C++20, such as: Is it possible to use std::string in a constexpr?
Sorry, C++ does not currently support the use of string literals (or real literals) as template parameters.
But re-reading your question, is that what you are asking? You cannot say:
foo <"bar"> x;
but you can say
template <typename T>
struct foo {
foo( T t ) {}
};
foo <const char *> f( "bar" );
This is a solution with MPLLIBS to pass a strings as template arguments ( C++11 ).
#include <iostream>
#include <mpllibs/metaparse/string.hpp> // https://github.com/sabel83/mpllibs
#include <boost/mpl/string.hpp>
// -std=c++11
template<class a_mpl_string>
struct A
{
static const char* string;
};
template<class a_mpl_string>
const char* A< a_mpl_string >
::string { boost::mpl::c_str< a_mpl_string >::value }; // boost compatible
typedef A< MPLLIBS_STRING ( "any string as template argument" ) > a_string_type;
int main ( int argc, char **argv )
{
std::cout << a_string_type{}.string << std::endl;
return 0;
}
prints:
any string as template argument
The lib on github: https://github.com/sabel83/mpllibs
inline const wchar_t *GetTheStringYouWant() { return L"The String You Want"; }
template <const wchar_t *GetLiteralFunc(void)>
class MyType
{
void test()
{
std::cout << GetLiteralFunc;
}
}
int main()
{
MyType<GetTheStringYouWant>.test();
}
Try it with pasing the address of a function as the template argument.
EDIT: ok the title of your question seems to be misleading
"I want a class which takes two parameters in its constructor. The first can be either an int, double or float, so , and the second is always a string literal "my string", so I guess const char * const."
It looks like you're trying to achieve:
template<typename T>
class Foo
{
public:
Foo(T t, const char* s) : first(t), second(s)
{
// do something
}
private:
T first;
const char* second;
};
This would work for any type, for the first parameter: int, float, double, whatever.
Now if you really want to restrict the type of the first parameter to be only int, float or double; you can come up with something more elaborate like
template<typename T>
struct RestrictType;
template<>
struct RestrictType<int>
{
typedef int Type;
};
template<>
struct RestrictType<float>
{
typedef float Type;
};
template<>
struct RestrictType<double>
{
typedef double Type;
};
template<typename T>
class Foo
{
typedef typename RestrictType<T>::Type FirstType;
public:
Foo(FirstType t, const char* s) : first(t), second(s)
{
// do something
}
private:
FirstType first;
const char* second;
};
int main()
{
Foo<int> f1(0, "can");
Foo<float> f2(1, "i");
Foo<double> f3(1, "have");
//Foo<char> f4(0, "a pony?");
}
If you remove the comment on the last line, you'll effectively get a compiler error.
String literals are not allowed by C++2003
ISO/IEC 14882-2003 §14.1:
14.1 Template parameters
A non-type template-parameter shall have one of the following (optionallycv-qualified) types:
— integral or enumeration type,
— pointer to object or pointer to function,
— reference to object or reference to function,
— pointer to member.
ISO/IEC 14882-2003 §14.3.2:
14.3.2 Template non-type arguments
A template-argument for a non-type, non-template template-parameter shall be one of:
— an integral constant-expression of integral or enumeration type; or
— the name of a non-type template-parameter; or
— the address of an object or function with external linkage, including function templates and function template-ids but excluding non-static class members, expressed as & id expression where the & is optional if the name refers to a function or array, or if the corresponding template-parameter is a reference; or
— a pointer to member expressed as described in 5.3.1.
[Note:A string literal (2.13.4) does not satisfy the requirements of any of these categories and thus is not an acceptable template-argument.
[Example:
template<class T, char* p> class X {
//...
X();
X(const char* q) { /* ... */ }
};
X<int,"Studebaker"> x1; //error: string literal as template-argument
char p[] = "Vivisectionist";
X<int,p> x2; //OK
—end example] —end note]
And it looks like it's not going to change in the upcoming C++0X, see the current draft 14.4.2 Template non-type arguments.
Based on your comments under Niel's answer, another possibility is the following:
#include <iostream>
static const char* eventNames[] = { "event_A", "event_B" };
enum EventId {
event_A = 0,
event_B
};
template <int EventId>
class Event
{
public:
Event() {
name_ = eventNames[EventId];
}
void print() {
std::cout << name_ << std::endl;
}
private:
const char* name_;
};
int main()
{
Event<event_A>().print();
Event<event_B>().print();
}
prints
event_A
event_B
You cannot pass a string literal directly as a template parameter.
But you can get close:
template<class MyString = typestring_is("Hello!")>
void MyPrint() {
puts( MyString::data() );
}
...
// or:
MyPrint<typestring_is("another text")>();
...
All you need is a small header file from here.
Alternatives:
Define a global char const * and pass it to the template as pointer. (here)
Drawback: Requires additional code outside of the template argument list. It is not suitable, if you need to specify the string literal "inline".
Use a non-standard language extension. (here)
Drawback: Not guaranteed to work with all compilers.
Use BOOST_METAPARSE_STRING. (here)
Drawback: Your code will depend on the Boost library.
Use a variadic template parameter pack of char, e.g. str_t<'T','e','s','t'>.
This is what the above solution does for you behind the scenes.
Use proxy static constexpr const char type_name_str[] = {"type name"}; for passing string as template parameter. Defining string using [] is important.
#include <iostream>
template<typename T, const char* const t_name>
struct TypeName
{
public:
static constexpr const char* Name()
{
return t_name;
};
};
static constexpr const char type_name_str[] = {"type name"};
int main()
{
std::cout<<TypeName<float, type_name_str>::Name();
return 0;
}
I want a class which takes two parameters in its constructor. The first can be either an int, double or float, so , and the second is always a string literal "my string"
template<typename T>
class demo
{
T data;
std::string s;
public:
demo(T d,std::string x="my string"):data(d),s(x) //Your constructor
{
}
};
I am not sure but is this something what you want?
Maybe not what the OP is asking, but if you use boost, you can create a macro like this for example:
#define C_STR(str_) boost::mpl::c_str< BOOST_METAPARSE_STRING(str_) >::value
Then use as follows:
template<const char* str>
structe testit{
};
testit<C_STR("hello")> ti;
template <char... elements>
struct KSym /* : optional_common_base */ {
// We really only care that we have a unique-type and thus can exploit being a `""_ksym singleton`
const char z[sizeof...(elements) + 1] = { elements..., '\0' };
// We can have properties, we don't need anything to be constexpr for Rs
};
template <typename T, T... chars>
auto&& operator""_ksym() {
static KSym<chars...> kSym; // Construct the unique singleton (lazily on demand)
return kSym;
}
static auto ksym_example1 = "a unique string symbol1\n"_ksym.z;
static auto ksym_example2 = "a unique string symbol2\n"_ksym.z;
auto dont_care = []() {
::OutputDebugString(ksym_example1);
::OutputDebugString("a unique string symbol2\n"_ksym.z);
assert("a unique string symbol1\n"_ksym.z == ksym_example1);
assert("a unique string symbol2\n"_ksym.z == ksym_example2);
return true;
}();
The above is working for me in production using Clang 11 on Windows.
(edited) I now use exactly this in clang on Windows:
// P0424R1: http://www.open-std.org/jtc1/SC22/wg21/docs/papers/2017/p0424r1.pdf
template <char... chars_ta> struct KSymT;
template <typename T, T... chars_ta> // std::move(KSymT<chars_ta...>::s);
auto operator""_ksym()->KSymT<chars_ta...>& { return KSymT<chars_ta...>::s; }
struct KSym {
virtual void onRegister() {}
virtual std::string_view zview_get() = 0;
};
template <char... chars_ta>
struct KSymT : KSym {
inline static KSymT s;
// We really only care that we have a unique-type and thus can exploit being a `""_ksym singleton`
inline static constexpr char z[sizeof...(chars_ta) + 1] = { chars_ta..., '\0' };
inline static constexpr UIntPk n = sizeof...(chars_ta);
// We can have properties, we don't need anything to be constexpr for Rs
virtual std::string_view zview_get() { return std::string_view(z); };
//#KSym-support compare with `Af_CmdArgs`
inline bool operator==(const Af_CmdArgs& cmd) {
return (cmd.argl[0] == n && memcmp(cmd.argv[0], z, n) == 0);
}
};
I was struggling with a similar problem and finally came up with a concise implementation that unpacks the string literal into a char... template parameter pack and without using the GNU literal operator template extension:
#include <utility>
template <char ...Chars>
struct type_string_t {
static constexpr const char data[sizeof...(Chars)] = {Chars...};
};
template <char s(std::size_t), std::size_t ...I>
auto type_string_impl(std::index_sequence<I...>) {
return type_string_t<s(I)...>();
}
#define type_string(s) \
decltype (type_string_impl<[] -> constexpr (std::size_t i) {return s[i];}> \
(std::make_index_sequence<sizeof (s)>()))
static_assert (std::is_same<type_string("String_A"),
type_string("String_A")>::value);
static_assert (!std::is_same<type_string("String_A"),
type_string("String_B")>::value);
A major caveat: this depends on a C++20 feature (class values as non-type template arguments; P0732, P1907), which (as of December 2020) is only (partially) implemented in GCC 9 and later (preprocessor feature test: (__cpp_nontype_template_args >= 201911L) || (__GNUG__ >= 9)). However, since the feature is standard, it is only a matter of time before other compilers catch up.
Another C++20 solution I don't see mentioned, but which was sufficiently simple and suitable for my own needs, is to use a constexpr lambda as the NTTP returning the string:
#include <string_view>
template<auto getStrLambda>
struct MyType {
static constexpr std::string_view myString{getStrLambda()};
};
int main() {
using TypeWithString = MyType<[]{return "Hello world!";}>;
return 0;
}
Compiler explorer example here.
here is a solution and extensions/examples
my solution extends https://ctrpeach.io/posts/cpp20-string-literal-template-parameters/
#include <iostream>
#include <algorithm>
#include <string>
template<size_t N>
struct StringLiteral {
char value[N];
constexpr StringLiteral(const char(&str)[N]) {
std::copy_n(str, N, value);
}
};
template <StringLiteral T>
struct String {
static constexpr std::string str() {
return T.value;
}
};
template <typename... Strings>
struct JoinedString {
static constexpr std::string str() {
return (Strings::str() + ...);
}
};
template <typename Delim, typename String, typename... Strings>
struct DelimJoinedString {
static constexpr std::string str() {
if constexpr (sizeof...(Strings))
return JoinedString<String, Delim, DelimJoinedString<Delim, Strings...>>::str();
else
return String::str();
}
};
int main() {
// "123"
using s123 = String<"123">;
std::cout << s123::str() << "\n";
// "abc"
using abc = String<"abc">;
std::cout << abc::str() << "\n";
// "abc123abc123"
using abc123abc123 = JoinedString<abc, s123, abc, s123>;
std::cout << abc123abc123::str() << "\n";
// "abc, 123"
using abccomma123 = DelimJoinedString<String<", ">, abc, s123>;
std::cout << abccomma123::str() << "\n";
// "abc, 123, 123, abc"
using commaabc123123abc = DelimJoinedString<String<", ">, abc, s123, s123, abc>;
std::cout << commaabc123123abc::str() << "\n";
return 0;
}
a string literal "my string", so I guess const char * const
Actually, string literals with n visible characters are of type const char[n+1].
#include <iostream>
#include <typeinfo>
template<class T>
void test(const T& t)
{
std::cout << typeid(t).name() << std::endl;
}
int main()
{
test("hello world"); // prints A12_c on my compiler
}