I have this code
#include <iostream>
size_t F()
{
return 0;
}
template <class Type, class... NextTypes>
size_t F(const Type& type, const NextTypes&... nextTypes)
{
if (!std::is_const<Type>::value)
return sizeof(type) + F(nextTypes...);
else
return F(nextTypes...);
}
int main()
{
int a = 0;
const int b = 0;
const size_t size = F(a,b);
std::cout << "size = " << size << std::endl;
return 0;
}
I'm trying to know in compilation time the total size of constant parameters and non const parameters. The current out put is 8, for some reason the compiler thinks b
is not constant, I used typeid
and decltype
to print the types of a
and b
and indeed the output shows b
is an int
and not const int
as I expected. What am I missing? Is it possible to separate a variadic set of arguments to const arguments and non const?
Consider this function template:
template<typename T>
void deduce(const T&);
If you let the compiler deduce a type for T
from an argument expression, the deduced type will never be const
: It will try to make the const T
of the function parameter identical to the type of the argument expression used to call the function. For example:
struct cls {};
const cls c;
deduce(c) // deduces T == cls
By deducing T == cls
, the compiler succeeds in making const T
identical to the argument type const cls
. There is no reason for the compiler to produce two different functions for const- and non-const argument types; the parameter type of the function template instantiation will be const-qualified in any case: you requested it by saying const T&
instead of, say, T&
.
You can deduce the const-ness of an argument by not cv-qualifying the function parameter:
template<typename T>
void deduce(T&);
However, this will fail to bind to non-const temporaries (rvalues). To support them as well, you can use universal references:
template<typename T>
void deduce(T&&);
This will deduce an lvalue-reference type for T
if the argument is an lvalue, and no reference if the argument is an rvalue. The const-ness will be deduced correctly.
For example, if the argument has the type const A
and is an lvalue, T
will be deduced to const A&
. The function parameter then is const A& &&
, which is collapsed to const A&
(an lvalue-reference). If the argument is an rvalue, T
will be deduced to const A
, and the function parameter becomes const A&&
(an rvalue-reference).
Note that since T
can be a reference in this case, you need to remove that before checking for const-ness: std::is_const< typename std::remove_reference<T>::type >::value
.