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.
Related
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, "")
I am converting a project written in C++ for windows. Everything is going fine (meaning I clearly see what needs to be changed to make things proper C++) until I hit this, which is my own little routine to find a keyword in along string of keyword=value pairs:
bool GetParameter(const char * haystack, const char *needle) {
char *search, *start;
int len;
len = strlen(needle) + 4; // make my own copy so I can upper case it...
search = (char *) calloc(1,len);
if (search == NULL) return false;
strcpy(search,needle);
strupr(search);
strcat(search,"="); // now it is 'KEYWORD='
start = strstr(haystack,search); <---- ERROR from compiler
g++ is telling me "Invalid conversion from const char * to char * "
(the precise location of the complaint is the argument variable 'search' )
But it would appear that g++ is dyslexic. Because I am actually going the other way. I am passing in a char * to a const char *
(so the conversion is "from char * to const char *" )
The strstr prototype is char * strstr(const char *, const char *)
There is no danger here. Nothing in any const char * is being modified.
Why is it telling me this?
What can I do to fix it?
Thanks for any help.
The background to the problem is that C defines the function strstr as:
char* strstr(const char*, const char*);
This is because C doesn't allow overloaded functions, so to allow you to use strstr with both const and non-const strings it accepts const strings and returns non-const. This introduces a weakness in C's already fragile type-system, because it removes const-ness from a string. It is the C programmer's job to not attempt to write via a pointer returned from strstr if you pased in non-modifiable strings.
In C++ the function is replaced by a pair of overloaded functions, the standard says:
7. The function signature strstr(const char*, const char*) shall be replaced by the two declarations:
const char* strstr(const char* s1, const char* s2);
char* strstr( char* s1, const char* s2);
both of which shall have the same behavior as the original declaration.
This is type-safe, if you pass in a const string you get back a const string. Your code passes in a const string, so G++ is following the standard by returning a const string. You get what you asked for.
Your code compiles on Windows because apparently the standard library you were using on Windows doesn't provide the overloads and only provides the C version. That allows you to pass in const strings and get back a non-const string. G++ provides the C++ versions, as required by the standard. The error is telling you that you're trying to convert the const return value to a non-const char*. The solution is the assign the return value to a const char* instead, which is portable and compiles everywhere.
Error is not regarding the arguments to stsrtr. Compiler is complaining about the conversion of the 'const char *' returned by strstr. You can't assign it to *start which is just char *
You can try one of these:
const char *start;
or
string start(strstr(haystack,search));
Although declaring start as const char* might suffice, what seems more appropriate to me is to use std::string objects instead:
#include <string>
#include <cctype>
#include <algorithm>
bool GetParameter(const char * haystack, const char *needle) {
std::string hstr(haystack), nstr(needle);
std::transform(nstr.begin(), nstr.end(),nstr.begin(), ::toupper);
nstr += "=";
std::size_t found = hstr.find(nstr);
if (found != std::string::npos) {
... // "NEEDLE=" found
}
else {
...
}
...
}
The conversion it is complaining about is from strstr(...) to start. Change the declaration of start to const char* start;
you can use such like:
start = const_cast<char *>(strstr( haystack, static_cast<const char *>(search) ));
I read a question on the difference between:
const char*
and
const char[]
where as for a while, I though arrays were just syntactic sugar for pointers.
But something is bugging me, I have a pice of code similar to the following:
namespace SomeNamespace {
const char* str = { 'b', 'l', 'a', 'h' };
}
I get, error: scaler object 'str' requires one element in initializer.
So, I tried this:
namespace SomeNamespace {
const char str[] = { 'b', 'l', 'a', 'h' };
}
It worked, at first I thought this may have to do with the fact that an extra operation is applied
when it is a const char*, and GCC is never a fan of operations being performed outside a function (which is bad practice anyway), but the error does not seem to suggest so.
However in:
void Func() {
const char* str = { 'b', 'l', 'a', 'h' };
}
It compiles just fine as expected. Does anyone have any idea why this is so?
x86_64/i686-nacl-gcc 4(.1.4?) pepper 19 tool - chain (basically GCC).
First off, it doesn't make a difference if you try to use compound initialization at namespace scope or in a function: neither should work! When you write
char const* str = ...;
you got a pointer to a sequence of chars which can, e.g., be initialized with a string literal. In any case, the chars are located somewhere else than the pointer. On the other hand, when you write
char const str[] = ...;
You define an array of chars. The size of the array is determined by the number of elements on the right side and, e.g., becomes 4 your example { 'b', 'l', 'a', 'h' }. If you used, e.g., "blah" instead the size would, of course, be 5. The elements of the array are copied into the location where str is defined in this case.
Note that char const x[] can be equivalent to writing char const* x in some contexts: when you declare a function argument, char const x[] actually is the same as char const*.
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.
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, "")