C-Style Strings as template arguments?
A string literal cannot be used as a template argument.
Update: Nowadays, a few years after this question was asked and answered, it is possible to use string literals as template arguments. With C++11, we can use characters packs as template arguments (template<char ...c>
) and it is possible to pass a literal string to such a template.
This would work, however:
template <char const *str>
struct X
{
const char *GetString() const
{
return str;
}
};
char global_string[] = "String";
int main()
{
X<global_string> x;
cout<<x.GetString();
}
Passing a string literal as a type argument to a class template
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" );
Trying to pass string literals as template arguments
re: your OP: I'd like to know why a couple of them failed.
The comment by @NatanReed is correct:
- Your first snippet fails because
Get
needs aTYPE
and is given anobject
. - Your second snippet fails because it is illegal to define a template argument as reference to an object.
- until C++2003, that is. Then
reference to an object
became legal.
- until C++2003, that is. Then
Template arguments must be constants from a limited set of types.
- See: ISO/IEC 14882-2003 §14.1: Template parameters
- See: ISO/IEC 14882-2003 §14.3.2: Template non-type arguments
And even then, the String constexpr str = "hello";
must have external linkage. So putting it on the stack inside of main()
is not going to work.
Give this a try:
#include <iostream>
#include <string>
using namespace std;
struct String {
char const *m_sz;
constexpr String(char const *a_sz)
:
m_sz(a_sz) {}
};
template<String const &_rstr>
string const Get() {
return _rstr.m_sz;
}
extern String constexpr globally_visible_str = "hello";
int main() {
cout << Get<globally_visible_str>() << endl;
return 0;
}
Is passing literal string as template parameter not good
My question is if the compiler will deduce two independent functions, one is for char[4] and the other is for char[3]?
It will.
If I call many func with const char* as above, the compiler will generate many independent functions?
You don't call func
with const char*
. If you did call func
with only const char*
then there would be only one instantiation of the function template.
You call the function with const char[4]
and const char[3]
which do cause separate instantiations. There will be an instantiation for each unique sets of template arguments.
Is this stupid? Should I avoid this?
Depends on use case. In many cases, the optimiser simply expands all calls inline and the instantiations won't leave any trace of their theoretical existance in the generated assembly.
Why passing a string literal to a template calling std::format fails to compile?
After P2216, std::format
requires that the format string must be a core constant expression. In your case, the compilation fails because the function argument First
is not a constant expression.
The workaround is to use std::vformat
, which works for runtime format strings
template<typename First, typename... Args>
auto format1(First&& first, Args&&... args) {
return std::vformat(
std::forward<First>(first),
std::make_format_args(std::forward<Args>(args)...));
}
Demo
If you really want to use std::format
, you can pass in a lambda that returns a string literal
template<typename First, typename... Args>
auto format1(First first, Args&&... args) {
return std::format(first(), std::forward<Args>(args)...);
}
int main() {
std::cout << format1([]{ return "hi {} {}"; }, 123, 456);
}
Demo
Template argument string vs. int
You simply cannot have a template parameter of type std::string
. The rules for non-type template parameters are defined by the standard as follows (§14.1/4):
A non-type template-parameter shall have one of the following (optionally cv-qualified) types:
- integral or enumeration type,
- pointer to object or pointer to function,
- lvalue reference to object or lvalue reference to function,
- pointer to member,
std::nullptr_t
.
In addition (§14.1/7):
A non-type template-parameter shall not be declared to have floating point, class, or void type.
As std::string
is a class type, your instantiation of foo
is not allowed.
Related Topics
Why Does the Free() Function Not Return Memory to the Operating System
Memory Stability of a C++ Application in Linux
Hide or Crop Overlapping Text in Qlabel
Why Is There Not an Std::Is_Struct Type Trait
Floating Point Format for Std::Ostream
How to Compare Multiple Strings Inside an If Statement
Why Use Functors Over Functions
Converting Multidimensional Arrays to Pointers in C++
G++ Linking Order Dependency When Linking C Code to C++ Code
Why Is a NaïVe C++ Matrix Multiplication 100 Times Slower Than Blas
Error , Symbol 'Vector' Could Not Be Resolved
Building Glew on Windows with Mingw
Convert Windows Filetime to Second in Unix/Linux
Is the Memory Allocated for Struct Members Continguous? What If a Struct Member Is an Array
Invalid Conversion from 'Void*' to 'Char*' When Using Malloc