In c++, it's possible to define const static data members from within the class definition without defining it at namespace-scope. Doing so is valid so long as the constant is not ODR-used; this practice effectively does not provide a storage-backing in the translation-unit. For example:
#include <cstddef> // std::size_t
class my_string
{
public:
static const auto npos = static_cast<std::size_t>(-1);
};
I like to follow almost-always-auto guidelines where possible to achieve a consistent left-to-right readability while also keeping the typing generic. However, this is at odds with the few cases where you may actually want that symbol to be possibly ODR used. What I would like to do is:
#include "my_string.hpp"
const auto my_string::npos; // error!
However, this fails even under c++20 due to the type not being specified -- despite the fact that decltype(my_string::npos) is already known by this point. Ideally, I'd like the namespace-definition to not necessitate a change if ever the constant's type changes.
My question is: Is there any way to achieve a simple left-to-right syntax in such a scenario?
The only two ways I can think of to solve this are to either not specify the namespace-definition using c++17's inline variables, or to name the type by using decltype(my_string::npos) (which, though ugly, does work).
despite the fact that decltype(my_string::npos) is already known by this point
Well.. so just use it!
#include <cstddef> // std::size_t
class my_string {
public:
static const auto npos = static_cast<std::size_t>(-1);
};
const decltype(my_string::npos) my_string::npos; // all fine!
Related
C++14 will allow the creation of variables that are templated. The usual example is a variable 'pi' that can be read to get the value of the mathematical constant π for various types (3 for int; the closest value possible with float, etc.)
Besides that we can have this feature just by wrapping a variable within a templated struct or class, how does this mix with type conversions? I see some overlapping.
And other than the pi example, how would it work with non-const variables? Are there any usage examples to understand how to make the most of such a feature and what its purpose is?
And other than the pi example, how would it work with non-const
variables?
Currently, it seems to instantiate the variables separately for the type. i.e., you could assign 10 to n<int> and it would be different from the template definition.
template<typename T>
T n = T(5);
int main()
{
n<int> = 10;
std::cout << n<int> << " "; // 10
std::cout << n<double> << " "; // 5
}
If the declaration is const, it is readonly. If it's a constexpr, like all constexpr declarations, it has not much use outside constexpr(ressions).
Besides that we can have this feature just by wrapping a variable
within a templated struct or class, how does this mix with type
conversions?
It's meant to be a simple proposal. I am unable to see how it affects type conversions in a significant way. As I already stated, the type of the variable is the type you instantiated the template with. i.e., decltype(n<int>) is int. decltype((double)n<int>) is double and so on.
Any usage example to understand how to make the most of such a feature
and what its purpose is?
N3651 provides a succinct rationale.
Alas, existing C++ rules do not allow a template declaration to
declare a variable. There are well known workarounds for this
problem:
• use constexpr static data members of class templates
• use constexpr function templates returning the desired values
These workarounds have been known for decades and well documented.
Standard classes such as std::numeric_limits are archetypical
examples. Although these workarounds aren’t perfect, their drawbacks
were tolerable to some degree because in the C++03 era only simple,
builtin types constants enjoyed unfettered direct and efficient
compile time support. All of that changed with the adoption of
constexpr variables in C++11, which extended the direct and efficient
support to constants of user-defined types. Now, programmers are
making constants (of class types) more and more apparent in programs.
So grow the confusion and frustrations associated with the
workarounds.
...
The main problems with "static data member" are:
• they require "duplicate" declarations: once inside the class
template, once outside the class template to provide the "real"
definition in case the con- stants is odr-used.
• programmers are both miffed and confused by the necessity of providing twice the same
declaration. By contrast, "ordinary" constant declarations do not need
duplicate declarations.
...
Well known examples in this category are probably static member
functions of numeric_limits, or functions such as
boost::constants::pi<T>(), etc. Constexpr functions templates do not
suffer the "duplicate declarations" issue that static data members
have; furthermore, they provide functional abstraction. However, they
force the programmer to chose in advance, at the definition site, how
the constants are to be delivered: either by a const reference, or by
plain non- reference type. If delivered by const reference then the
constants must be systematically be allocated in static storage; if
by non-reference type, then the constants need copying. Copying isn’t
an issue for builtin types, but it is a showstopper for user-defined
types with value semantics that aren’t just wrappers around tiny
builtin types (e.g. matrix, or integer, or bigfloat, etc.) By
contrast, "ordinary" const(expr) variables do not suffer from this
problem. A simple definition is provided, and the decision of
whether the constants actually needs to be layout out in storage only
depends on the usage, not the definition.
we can have this feature just by wrapping a variable within a templated struct or class
Yes, but that would be gratuitous syntactic salt. Not healthy for the blood pressure.
pi<double> conveys the intent better than pi<double>::value. Short and to the point. That's enough of a reason in my book to allow and encourage this syntax.
Another practical example for C++14's variable templates is when you need a function for passing something into std::accumulate:
template<typename T>
T const & (*maxer) (T const &, T const &) = std::max<T>;
std::accumulate(some.begin(), some.end(), initial, maxer<float>);
Note that using std::max<T> is insufficient because it can't deduce the exact signature. In this particular example you can use max_element instead, but the point is that there is a whole class of functions that share this behavior.
I wonder whether something along these lines would be possible: (assuming availability of template lambdas)
void some_func() {
template<typename T>
std::map<int, T> storage;
auto store = []<typename T>(int key, const T& value) { storage<T>[key] = value; };
store(0, 2);
store(1, "Hello"s);
store(2, 0.7);
// All three values are stored in a different map, according to their type.
}
Now, is this useful?
As a simpler use, notice that the initialization of pi<T> uses explicit conversion (explicit call of a unary constructor) and not uniform initialization. Which means that, given a type radians with a constructor radians(double), you can write pi<radians>.
Well, you can use this to write compile time code like this:
#include <iostream>
template <int N> const int ctSquare = N*N;
int main() {
std::cout << ctSquare<7> << std::endl;
}
This is a significant improvement over the equivalent
#include <iostream>
template <int N> struct ctSquare {
static const int value = N*N;
};
int main() {
std::cout << ctSquare<7>::value << std::endl;
}
that people used to write to perform template metaprogramming before variable templates were introduced. For non-type values, we were able to do this since C++11 with constexpr, so template variables have only the advantage of allowing computations based on types to the variable templates.
TL;DR: They don't allow us to do anything we couldn't do before, but they make template metaprogramming less of a PITA.
I have a use case here.
template<typename CT> constexpr CT MARK = '%';
template<> constexpr wchar_t MARK<wchar_t> = L'%';
which are used in a string processing template.`
template <typename CT>
void ProcessString(const std::basic_string<CT>& str)
{
auto&& markpos = str.find(MARK<CT>);
...
}
the basic_string class has npos which declared as static const.
Why it declares as static const since C++11, why not simple as:
class basic_string{
................................
enum: size_type { npos = static_cast<size_type>(-1) };
.........................>
};
???
which is good, static const or enum ?
There is a good reason not to do that, the enumeration creates a new type which will at least cause changes when resolving overloads or instantiating templates.
That said, I believe that you can actually declare and define class-static constants in the class definition, or is there some exception to that rule when the class is a template?
The two solutions are pretty much the same. The so called enum hack was born because of compilers which didn't support for in class initialization, mostly. The differences are: you cannot take the address of the enum "variable"; the static const approach is type-safe. Now, in C++11 enum classes are indeed type safe (except you stick to enums).
Basically, then, the only difference is in the "address of" issue. But, when you define an enum class you are defining a type; you might well find it to be bad looking to define a type when what you need is a constant.
I was recently asked by a student about a compile issue. The answer was quite simple but right now I am struggling about the reason.
A simple example:
#include <iostream>
#include <vector>
struct MyStruct
{
typedef std::vector<int> MyIntVector;
MyIntVector CopyVector(MyIntVector const& vector);
};
MyStruct::MyIntVector MyStruct::CopyVector(MyIntVector const& vector)
^^^^^^^^
{
MyIntVector vec;
return vec;
}
int main(int /*argc*/, char** /*argv*/)
{
MyStruct st;
}
To be valid c++ code the return parameter has to be fully qualified. So much to the answer and to make the compiler/student happy.
But why has the return value to be qualified with the class and the parameter to the function not?
I always did this and I know that it has to do with the ADL lookup, but now that I was asked I searching for a better answer.
Can anyone give a me reference to the spec or a hint where I can find some more information?
The structure of the grammar is such that the return type is independant of what is declared and it is possible to declare (but not define) several things with the same type. This is valid C++:
int f(int), g(int);
so having the precise scope of the declared objects influencing the lookup for the type would be problematic. In
id1 ns1::f(int), ns2::g(int);
where would id1 be looked up?
One could have added special rules to use in function definition (there can be only one function definition -- so there would be no ambiguity --, but can be several object one), but I'm not sure the possibility has been examined, and I think the added complication would not be compensated by the advantage.
To proceed with parsing, the compiler needs to figure out what is a typename and what is not.
The only thing that can occur at namespace scope is a declaration, and most C++ declarations begin with a typename, but this is not the case in C. Putting a stray, undefined identifier at toplevel scope in a C program declares it to be an int with static visibility.
Regardless of the possibility of compiling a program, it also makes the parser much simpler if it can proceed from beginning to end without queuing up tokens for later identification within the context of the class.
C++11 solves the problem with trailing-return-type syntax:
auto MyStruct::CopyVector(MyIntVector const& vector) -> MyIntVector {
I have a class declaration(.h file) like so:
struct MyClass {
static const uint32_t SIZE = sizeof(MyType);
};
When linking my program together, I get linker errors for MyClass::SIZE. nm confirms that the symbol is undefined. http://forums.devshed.com/c-programming-42/linker-errors-undefined-reference-to-static-member-data-193010.html seems to address my problem, indicating that "class static objects must also be declared outside any function or class just like normal globals."
I have two questions:
Is this explanation valid for my case? If so, can you explain in a little more detail why this is true?
What's the best way to fix it? I'd like to keep this member's initialization entirely in the .h file.
Your problem may have nothing to do with someone taking the address of your variable. It could simply be the compiler opting not to use the variable as a constant expression even though it could. For example:
f(int const&);
struct X { enum { enum_val = 42 }; static int const static_mem = 42; };
f(5);
f(X::enum_val);
f(X::static_mem);
In the first two cases the compiler is required to use the input as a constant expression and the const& can be initialized with such. The last case however is different. Even though your intent is probably to use static_mem as a constant expression, and its completely legitimate to do so, the compiler is free to do otherwise and some will actually create a reference to the variable itself. This is "use" of the variable and thus you're required to have a definition of that variable somewhere in the program.
There's two ways to fix this issue:
1) Add a definition to your program.
2) Use enum instead:
struct X
{
enum { static_mem = ? };
};
The first solution is necessary if you ever do intend that taking the address of your variable be possible. Chances are though that you did not or you would have created that definition already. The later solution forces the compiler to use X::static_mem as a constant expression since enum members don't actually exist as objects in the program. Based on your last statement in your question, I'm betting this is the solution you really want.
The standard requires a definition for a static member integral constant only if its address is taken, otherwise the declaration with an initializer (what you have) is enough. That linker error message should mention which object/function takes an address of MyClass::SIZE.
Quoting myself from No definition available for static const member with initializer?
And from 9.4.2/4:
If a static data member is of const
integral or const enumeration type,
its declaration in the class
definition can specify a
constant initializer which shall be an
integral constant expression (5.19).
In that case, the member can appear in
integral constant expressions within
its scope. The member shall still be
defined in a namespace scope if it is
used in the program and the namespace
scope definition shall not contain an
initializer.
From these references we can infer ("...shall still be defined..." in 9.4.2/4) that if it's not defined then the program isn't well-formed.
#David Rodríguez - dribeas points out that you must be taking the address of the static member in your program somewhere. If you can avoid taking the address then there's no need for the definition in the implementation file (alternately you aren't taking the address and have a buggy compiler). Otherwise you must have the definition.
If you've to do this:
//.h file
struct MyClass
{
static const uint32_t SIZE = sizeof(MyType); //this is declaration!
};
//.cpp file
const uint32_t MyClass::SIZE; //this is definition - necessary!
Most likely, but without any error messages, it's hard to say.
Use a static const int. You can initialize it in the header, and you don't need to declare it in the cpp.
I would like to define inside a class a constant which value is the maximum possible int. Something like this:
class A
{
...
static const int ERROR_VALUE = std::numeric_limits<int>::max();
...
}
This declaration fails to compile with the following message:
numeric.cpp:8: error: 'std::numeric_limits::max()' cannot appear in a constant-expression
numeric.cpp:8: error: a function call cannot appear in a constant-expression
I understand why this doesn't work, but two things look weird to me:
It seems to me a natural decision to use the value in constant expressions. Why did the language designers decide to make max() a function thus not allowing this usage?
The spec claims in 18.2.1 that
For all members declared static const in the numeric_limits template, specializations shall define these values in such a way that they are usable as integral constant expressions.
Doesn't it mean that I should be able to use it in my scenario and doesn't it contradict the error message?
Thank you.
Looks like a bit of a defect...
In C++0x, numeric_limits will have everything marked with constexpr, meaning you will be able to use min() and max() as compile-time constants.
While the current standard lacks support here, for integral types Boost.IntegerTraits gives you the compile time constants const_min and const_max.
The problem arises from §9.4.2/4:
If a static data member is of const integral or const enumeration type, its declaration in the class definition can specify a constant-initializer which shall be an integral constant expression (5.19). In that case, the member can appear in integral constant expressions.
Note that it adds:
The member shall still be defined in a name- space scope if it is used in the program and the namespace scope definition shall not contain an initializer.
As others already mentioned numeric_limits min() and max() simply aren't integral constant expressions, i.e. compile time constants.
You want:
#include <limits>
struct A {
static const int ERROR_VALUE;
};
const int A::ERROR_VALUE = std::numeric_limits<int>::max();
Put the class/struct in a header and the definition in a .cpp file.
It doesn't contradict, because max is not defined static const. It's just a static member function. Functions can't be const, and static member functions can't have a const attached at the very right either.
There is also a double max() in the double version of the limits, and in C++03 it wouldn't work to say static double const max = .... So to be consistent, max() is a function for all versions of the limit template.
Now, it's known that max() not being able to be used like that is bad, and C++0x already solves it by making it a constexpr function, allowing your proposed usage.
I will try to answer you as much as I understood from your question:
1- If you want a static const int in your program to be initialized with a function:
int Data()
{
return rand();
}
class A
{
public :
static const int ee;
};
const int A::ee=Data();
This works on VS 2008
2- If you want to get max and min number for a given data type, then use these definitions
INT_MAX, INT_MIN, LONG_MAX and so on..
3- If however you need to use these wrt template type, then
hard code the templates yourself
template<>
int MaxData()
{
return INT_MAX;
}
and
template<>
long MaxData()
{
return LONG_MAX ;
}
and call them like this
int y=MaxData<int>();
4- and if you are only dealing with binary represented types only, then use this:
template <class T>
T MaxData(){
return ~(1<<((sizeof(T)*8)-1));
}
and this
template <class T>
T MinData(){
return (1<<((sizeof(T)*8)-1));
}
Hope this can help you..