constant expression in c++ template argument - c++

I have a template, that takes a char argument like:
A<'T'>
I am storing my T in a variable like:
const char ch = str[0]; //str is a string from my program
constexpr char ch = str[0]; // this doesnt work either for me
I am trying to achieve this:
A<ch>();
I am using gcc 4.7 and have dabbled with constexpr but I havent been able to get that work
Any idea of a way to get this to work?
Any help is appreciated

This can only work if everything is a constant expression:
constexpr char str[] = "Hello World";
constexpr char ch = str[0];
A<ch> x;

If the contents of str are defined at runtime, then there is no way to achieve that. The compiler requires your template value to be set during compilation.
That is why this is valid:
A<'a'>();
Since 'a' is a constant value, known during compilation. But this:
void foo(const std::string &value) {
A<value[0]> t;
}
Is not, since value[0], despite being a constant value, is not known during compilation.

Related

Detecting string literals at compile time [duplicate]

I have a class to wrap string literals and calculate the size at compile time.
The constructor looks like this:
template< std::size_t N >
Literal( const char (&literal)[N] );
// used like this
Literal greet( "Hello World!" );
printf( "%s, length: %d", greet.c_str(), greet.size() );
There is problem with the code however. The following code compiles and I would like to make it an error.
char broke[] = { 'a', 'b', 'c' };
Literal l( broke );
Is there a way to restrict the constructor so that it only accepts c string literals? Compile time detection is preferred, but runtime is acceptable if there is no better way.
There is a way to force a string literal argument: make a user defined literal operator. You can make the operator constexpr to get the size at compile time:
constexpr Literal operator "" _suffix(char const* str, size_t len) {
return Literal(chars, len);
}
I don't know of any compiler that implements this feature at this time.
Yes. You can generate compile time error with following preprocessor:
#define IS_STRING_LITERAL(X) "" X ""
If you try to pass anything other than a string literal, the compilation will fail. Usage:
Literal greet(IS_STRING_LITERAL("Hello World!")); // ok
Literal greet(IS_STRING_LITERAL(broke)); // error
With a C++11 compiler with full support for constexpr we can use a constexpr constructor using a constexpr function, which compiles to a non-const expression body in case the trailing zero character precondition is not fulfilled, causing the compilation to fail with an error. The following code expands the code of UncleBens and is inspired by an article of Andrzej's C++ blog:
#include <cstdlib>
class Literal
{
public:
template <std::size_t N> constexpr
Literal(const char (&str)[N])
: mStr(str),
mLength(checkForTrailingZeroAndGetLength(str[N - 1], N))
{
}
template <std::size_t N> Literal(char (&str)[N]) = delete;
private:
const char* mStr;
std::size_t mLength;
struct Not_a_CString_Exception{};
constexpr static
std::size_t checkForTrailingZeroAndGetLength(char ch, std::size_t sz)
{
return (ch) ? throw Not_a_CString_Exception() : (sz - 1);
}
};
constexpr char broke[] = { 'a', 'b', 'c' };
//constexpr Literal lit = (broke); // causes compile time error
constexpr Literal bla = "bla"; // constructed at compile time
I tested this code with gcc 4.8.2. Compilation with MS Visual C++ 2013 CTP failed, as it still does not fully support constexpr (constexpr member functions still not supported).
Probably I should mention, that my first (and preferred) approach was to simply insert
static_assert(str[N - 1] == '\0', "Not a C string.")
in the constructor body. It failed with a compilation error and it seems, that constexpr constructors must have an empty body. I don't know, if this is a C++11 restriction and if it might be relaxed by future standards.
No there is no way to do this. String literals have a particular type and all method overload resolution is done on that type, not that it's a string literal. Any method which accepts a string literal will end up accepting any value which has the same type.
If your function absolutely depends on an item being a string literal to function then you probably need to revisit the function. It's depending on data it can't guarantee.
A string literal does not have a separate type to distinguish it from a const char array.
This, however, will make it slightly harder to accidentally pass (non-const) char arrays.
#include <cstdlib>
struct Literal
{
template< std::size_t N >
Literal( const char (&literal)[N] ){}
template< std::size_t N >
Literal( char (&literal)[N] ) = delete;
};
int main()
{
Literal greet( "Hello World!" );
char a[] = "Hello world";
Literal broke(a); //fails
}
As to runtime checking, the only problem with a non-literal is that it may not be null-terminated? As you know the size of the array, you can loop over it (preferable backwards) to see if there's a \0 in it.
I once came up with a C++98 version that uses an approach similar to the one proposed by #k.st. I'll add this for the sake of completeness to address some of the critique wrt the C++98 macro.
This version tries to enforce good behavior by preventing direct construction via a private ctor and moving the only accessible factory function into a detail namespace which in turn is used by the "offical" creation macro. Not exactly pretty, but a bit more fool proof. This way, users have to at least explicitly use functionality that is obviously marked as internal if they want to misbehave. As always, there is no way to protect against intentional malignity.
class StringLiteral
{
private:
// Direct usage is forbidden. Use STRING_LITERAL() macro instead.
friend StringLiteral detail::CreateStringLiteral(const char* str);
explicit StringLiteral(const char* str) : m_string(str)
{}
public:
operator const char*() const { return m_string; }
private:
const char* m_string;
};
namespace detail {
StringLiteral CreateStringLiteral(const char* str)
{
return StringLiteral(str);
}
} // namespace detail
#define STRING_LITERAL_INTERNAL(a, b) detail::CreateStringLiteral(a##b)
/**
* \brief The only way to create a \ref StringLiteral "StringLiteral" object.
* This will not compile if used with anything that is not a string literal.
*/
#define STRING_LITERAL(str) STRING_LITERAL_INTERNAL(str, "")

Why does "auto" declare strings as const char* instead of std::string?

I made a template which adds the data it is given. If I use it like this, the compiler declares in_1 and in_2 as const char *, and the code doesn't compile.
#include <iostream>
using namespace std;
template <class T>
T addstuff(T part_1, T part_2){
return(part_1+part_2);
}
int main(int argc, char const *argv[])
{
auto in_1="Shut ";
auto in_2="up.";
cout<<addstuff(in_1, in_2)<<endl;
return 0;
}
If I declare in_1 and in_2 std::string, it works like a charm.
Why can't (or doesn't) the compiler declare those strings automatically std::string?
The reason you can't "write" to your auto variable is that it's a const char * or const char [1], because that is the type of any string constant.
The point of auto is to resolve to the simplest possible type which "works" for the type of the assignment. The compiler does not "look forward to see what you are doing with the variable", so it doesn't understand that later on you will want to write into this variable, and use it to store a string, so std::string would make more sense.
You code could be made to work in many different ways, here's one that makes some sense:
std::string default_name = "";
auto name = default_name;
cin >> name;
If you use string literals, auto will work as expected.
In C++14, C++17 or C++20, you can place an s after the quotes, and it will create a std::string instead of a const char* string.
This can be used together with auto to create a std::string:
auto hello = "hello"s;
String literals are not enabled by default. One way of enabling string literals is to place the following at the top of the source file:
#include <string>
using namespace std::string_literals;
As an example, this loop works for std::string (with s added to the string literal), but not for const char* type string literals:
for (auto &x : hello) {
std::cout << "letter: " << x << std::endl;
}
Here is the cppreference page for the ""s operator.
Because string literals have type const char[N+1], not std::string.
This is just a fact of the language.
They could have made it so that auto has a special case for string literals, but that would be inconsistent, surprising and of very little benefit.
auto will declare the variable as the compile-time type of the expression you initialize it to.
String literals are of type const char*, not std::string.

Restrict passed parameter to a string literal

I have a class to wrap string literals and calculate the size at compile time.
The constructor looks like this:
template< std::size_t N >
Literal( const char (&literal)[N] );
// used like this
Literal greet( "Hello World!" );
printf( "%s, length: %d", greet.c_str(), greet.size() );
There is problem with the code however. The following code compiles and I would like to make it an error.
char broke[] = { 'a', 'b', 'c' };
Literal l( broke );
Is there a way to restrict the constructor so that it only accepts c string literals? Compile time detection is preferred, but runtime is acceptable if there is no better way.
There is a way to force a string literal argument: make a user defined literal operator. You can make the operator constexpr to get the size at compile time:
constexpr Literal operator "" _suffix(char const* str, size_t len) {
return Literal(chars, len);
}
I don't know of any compiler that implements this feature at this time.
Yes. You can generate compile time error with following preprocessor:
#define IS_STRING_LITERAL(X) "" X ""
If you try to pass anything other than a string literal, the compilation will fail. Usage:
Literal greet(IS_STRING_LITERAL("Hello World!")); // ok
Literal greet(IS_STRING_LITERAL(broke)); // error
With a C++11 compiler with full support for constexpr we can use a constexpr constructor using a constexpr function, which compiles to a non-const expression body in case the trailing zero character precondition is not fulfilled, causing the compilation to fail with an error. The following code expands the code of UncleBens and is inspired by an article of Andrzej's C++ blog:
#include <cstdlib>
class Literal
{
public:
template <std::size_t N> constexpr
Literal(const char (&str)[N])
: mStr(str),
mLength(checkForTrailingZeroAndGetLength(str[N - 1], N))
{
}
template <std::size_t N> Literal(char (&str)[N]) = delete;
private:
const char* mStr;
std::size_t mLength;
struct Not_a_CString_Exception{};
constexpr static
std::size_t checkForTrailingZeroAndGetLength(char ch, std::size_t sz)
{
return (ch) ? throw Not_a_CString_Exception() : (sz - 1);
}
};
constexpr char broke[] = { 'a', 'b', 'c' };
//constexpr Literal lit = (broke); // causes compile time error
constexpr Literal bla = "bla"; // constructed at compile time
I tested this code with gcc 4.8.2. Compilation with MS Visual C++ 2013 CTP failed, as it still does not fully support constexpr (constexpr member functions still not supported).
Probably I should mention, that my first (and preferred) approach was to simply insert
static_assert(str[N - 1] == '\0', "Not a C string.")
in the constructor body. It failed with a compilation error and it seems, that constexpr constructors must have an empty body. I don't know, if this is a C++11 restriction and if it might be relaxed by future standards.
No there is no way to do this. String literals have a particular type and all method overload resolution is done on that type, not that it's a string literal. Any method which accepts a string literal will end up accepting any value which has the same type.
If your function absolutely depends on an item being a string literal to function then you probably need to revisit the function. It's depending on data it can't guarantee.
A string literal does not have a separate type to distinguish it from a const char array.
This, however, will make it slightly harder to accidentally pass (non-const) char arrays.
#include <cstdlib>
struct Literal
{
template< std::size_t N >
Literal( const char (&literal)[N] ){}
template< std::size_t N >
Literal( char (&literal)[N] ) = delete;
};
int main()
{
Literal greet( "Hello World!" );
char a[] = "Hello world";
Literal broke(a); //fails
}
As to runtime checking, the only problem with a non-literal is that it may not be null-terminated? As you know the size of the array, you can loop over it (preferable backwards) to see if there's a \0 in it.
I once came up with a C++98 version that uses an approach similar to the one proposed by #k.st. I'll add this for the sake of completeness to address some of the critique wrt the C++98 macro.
This version tries to enforce good behavior by preventing direct construction via a private ctor and moving the only accessible factory function into a detail namespace which in turn is used by the "offical" creation macro. Not exactly pretty, but a bit more fool proof. This way, users have to at least explicitly use functionality that is obviously marked as internal if they want to misbehave. As always, there is no way to protect against intentional malignity.
class StringLiteral
{
private:
// Direct usage is forbidden. Use STRING_LITERAL() macro instead.
friend StringLiteral detail::CreateStringLiteral(const char* str);
explicit StringLiteral(const char* str) : m_string(str)
{}
public:
operator const char*() const { return m_string; }
private:
const char* m_string;
};
namespace detail {
StringLiteral CreateStringLiteral(const char* str)
{
return StringLiteral(str);
}
} // namespace detail
#define STRING_LITERAL_INTERNAL(a, b) detail::CreateStringLiteral(a##b)
/**
* \brief The only way to create a \ref StringLiteral "StringLiteral" object.
* This will not compile if used with anything that is not a string literal.
*/
#define STRING_LITERAL(str) STRING_LITERAL_INTERNAL(str, "")

Static check const char* contains spaces

Is there a way to check (assert) at compile time wether a const char* contains spaces or not?
Something like:
const char* cstr1 = "ok";
const char* cstr2 = "very bad";
check( cstr1 ); //OK
check( cstr2 ); //Fail to compile
The type is the same, but it may be possible to define some tricky template metaprogramming tecnique to do it.
Point is, all the info required is fixed at compile time.
This problem should be related to the "From const char variable to type" problem, which I think can be solved by compile-time hashing via metaprogramming tecniques.
Thank you in advance for your help.
You can't use ordinary strings since their characters cannot be accessed by templates, but you can use MPL strings:
#include <boost/mpl/char.hpp>
#include <boost/mpl/string.hpp>
#include <boost/mpl/contains.hpp>
#include <boost/utility/enable_if.hpp>
typedef boost::mpl::char_<' '> space;
typedef boost::mpl::string<'o', 'k'> cstr1;
typedef boost::mpl::string<'v', 'e', 'r', 'y', ' ', 'b', 'a', 'd'> cstr2;
boost::disable_if< boost::mpl::contains<cstr1, space> >::type check();
// boost::disable_if< boost::mpl::contains<cstr2, space> >::type check();
The second line fails to compile.
The problem is that you don't know cstr at compile time.
int i = function_call();
const char* cstr = NULL;
if(i > 0)
{
cstr = "hello";
}
else
{
cstr = "ciaooo";
}
Consider the example above. The compiler does not now what value const char* cstr will assume until runtime.
Basically I would say you can't make such check at compile time.
Note that though being declared as const this does not mean the variable cstr is constant. Note that the pointer type is const. You have to read it like this: (const char)* cstr. This means you cannot perform such operations cstr[0] = 's';
A pure constant would be declared like this:
const char * const CONSTANT = "test";
A new assignment would fail at compile time. Even if you used this approach, I don't think there is a possibility to evaluate the content of the constant at compile time.
I don't think so. If that was possible, how would the compiler manage to check this at compile time?
const char* cstr3 = some_dynamic_function();
check( cstr3 );
Write a script that checks the string literals that you care about, and fails if any of them have spaces.
Run this script during your build process.
Make the success of your build process dependent upon the success of the script.

C++ deprecated conversion from string constant to 'char*'

I have a class with a private char str[256];
and for it I have an explicit constructor:
explicit myClass(char *func)
{
strcpy(str,func);
}
I call it as:
myClass obj("example");
When I compile this I get the following warning:
deprecated conversion from string constant to 'char*'
Why is this happening?
This is an error message you see whenever you have a situation like the following:
char* pointer_to_nonconst = "string literal";
Why? Well, C and C++ differ in the type of the string literal. In C the type is array of char and in C++ it is constant array of char. In any case, you are not allowed to change the characters of the string literal, so the const in C++ is not really a restriction but more of a type safety thing. A conversion from const char* to char* is generally not possible without an explicit cast for safety reasons. But for backwards compatibility with C the language C++ still allows assigning a string literal to a char* and gives you a warning about this conversion being deprecated.
So, somewhere you are missing one or more consts in your program for const correctness. But the code you showed to us is not the problem as it does not do this kind of deprecated conversion. The warning must have come from some other place.
The warning:
deprecated conversion from string constant to 'char*'
is given because you are doing somewhere (not in the code you posted) something like:
void foo(char* str);
foo("hello");
The problem is that you are trying to convert a string literal (with type const char[]) to char*.
You can convert a const char[] to const char* because the array decays to the pointer, but what you are doing is making a mutable a constant.
This conversion is probably allowed for C compatibility and just gives you the warning mentioned.
As answer no. 2 by fnieto - Fernando Nieto clearly and correctly describes that this warning is given because somewhere in your code you are doing (not in the code you posted) something like:
void foo(char* str);
foo("hello");
However, if you want to keep your code warning-free as well then just make respective change in your code:
void foo(char* str);
foo((char *)"hello");
That is, simply cast the string constant to (char *).
There are 3 solutions:
Solution 1:
const char *x = "foo bar";
Solution 2:
char *x = (char *)"foo bar";
Solution 3:
char* x = (char*) malloc(strlen("foo bar")+1); // +1 for the terminator
strcpy(x,"foo bar");
Arrays also can be used instead of pointers because an array is already a constant pointer.
Update: See the comments for security concerns regarding solution 3.
A reason for this problem (which is even harder to detect than the issue with char* str = "some string" - which others have explained) is when you are using constexpr.
constexpr char* str = "some string";
It seems that it would behave similar to const char* str, and so would not cause a warning, as it occurs before char*, but it instead behaves as char* const str.
Details
Constant pointer, and pointer to a constant. The difference between const char* str, and char* const str can be explained as follows.
const char* str : Declare str to be a pointer to a const char. This means that the data to which this pointer is pointing to it constant. The pointer can be modified, but any attempt to modify the data would throw a compilation error.
str++ ; : VALID. We are modifying the pointer, and not the data being pointed to.
*str = 'a'; : INVALID. We are trying to modify the data being pointed to.
char* const str : Declare str to be a const pointer to char. This means that point is now constant, but the data being pointed too is not. The pointer cannot be modified but we can modify the data using the pointer.
str++ ; : INVALID. We are trying to modify the pointer variable, which is a constant.
*str = 'a'; : VALID. We are trying to modify the data being pointed to. In our case this will not cause a compilation error, but will cause a runtime error, as the string will most probably will go into a read only section of the compiled binary. This statement would make sense if we had dynamically allocated memory, eg. char* const str = new char[5];.
const char* const str : Declare str to be a const pointer to a const char. In this case we can neither modify the pointer, nor the data being pointed to.
str++ ; : INVALID. We are trying to modify the pointer variable, which is a constant.
*str = 'a'; : INVALID. We are trying to modify the data pointed by this pointer, which is also constant.
In my case the issue was that I was expecting constexpr char* str to behave as const char* str, and not char* const str, since visually it seems closer to the former.
Also, the warning generated for constexpr char* str = "some string" is slightly different from char* str = "some string".
Compiler warning for constexpr char* str = "some string": ISO C++11 does not allow conversion from string literal to 'char *const'
Compiler warning for char* str = "some string": ISO C++11 does not allow conversion from string literal to 'char *'.
Tip
You can use C gibberish ↔ English converter to convert C declarations to easily understandable English statements, and vice versa. This is a C only tool, and thus wont support things (like constexpr) which are exclusive to C++.
In fact a string constant literal is neither a const char * nor a char* but a char[]. Its quite strange but written down in the c++ specifications; If you modify it the behavior is undefined because the compiler may store it in the code segment.
Maybe you can try this:
void foo(const char* str)
{
// Do something
}
foo("Hello")
It works for me
I solve this problem by adding this macro in the beginning of the code, somewhere. Or add it in <iostream>, hehe.
#define C_TEXT( text ) ((char*)std::string( text ).c_str())
I also got the same problem. And what I simple did is just adding const char* instead of char*. And the problem solved. As others have mentioned above it is a compatible error. C treats strings as char arrays while C++ treat them as const char arrays.
For what its worth, I find this simple wrapper class to be helpful for converting C++ strings to char *:
class StringWrapper {
std::vector<char> vec;
public:
StringWrapper(const std::string &str) : vec(str.begin(), str.end()) {
}
char *getChars() {
return &vec[0];
}
};
The following illustrates the solution, assign your string to a variable pointer to a constant array of char (a string is a constant pointer to a constant array of char - plus length info):
#include <iostream>
void Swap(const char * & left, const char * & right) {
const char *const temp = left;
left = right;
right = temp;
}
int main() {
const char * x = "Hello"; // These works because you are making a variable
const char * y = "World"; // pointer to a constant string
std::cout << "x = " << x << ", y = " << y << '\n';
Swap(x, y);
std::cout << "x = " << x << ", y = " << y << '\n';
}