Recursively unpacking a template pack for a parameter-less function - c++14

I'm trying to create a struct template with a variadic template type pack, that can deduct the sum of the size of all types passed in.
Below you find a simplified example, in the real-world context, the size computed is used to create further member objects.
template <typename... Types>
struct OverallSize
{
template <typename FirstType, typename... NextTypes>
static constexpr size_t sizesum() { return sizeof (FirstType) + sizesum<NextTypes...>(); }
template <typename LastType>
static constexpr size_t sizesum() { return sizeof (LastType); }
static constexpr size_t size = sizesum<Types...>();
};
// Should work e.g. like this
auto s = OverallSize<int, float, char>::size; // s will be 9 on x86-64
I'm used to this recursive parameter unpacking approach when it comes to argument lists and assumed this works as well with argument-less functions and explicit template specification. However I get the following error when compiling with clang
Call to 'sizesum' is ambiguous
...
Candidate function [with FirstType = unsigned long, NextTypes = <>]
Candidate function [with LastType = unsigned long]
So it seems as if the last recursion iteration doesn't work here – not sure why the compiler doesn't simply chose the most obvious choice: The one with only one template type – just as it would happen if there was an actual template argument passed to the function.
So, what do I have to do to make this compile and work as desired?

For C++14 you can use SFINAE:
template <
typename FirstType,
typename... NextTypes,
std::enable_if_t<sizeof...(NextTypes) >= 1>* = nullptr >
static constexpr size_t sizesum() {
return sizeof (FirstType) + sizesum<NextTypes...>();
}
this template will be considered only if parameters pack has size >= 1.
Demo

Related

C++11: Variadic template deduction logic

I have the following construct:
template <class... Args>
class some_class
{
public:
some_class() = default;
some_class(Args...) = delete;
~some_class() = default;
};
template<>
class some_class<void>
{
public:
some_class() = default;
~some_class() = default;
};
The reason for this is that I just want to allow the users to create objects using the default constructor, so for example:
some_class<int,float> b;
should work but
some_class<int,float> c(1,3.4);
should give me a compilation error.
At some point in time I also needed to create templates based on void hence, the specialization for void:
some_class<void> a;
But by mistake I have typed:
some_class<> d;
And suddenly my code stopped compiling and it gave me the error:
some_class<Args>::some_class(Args ...) [with Args = {}]’ cannot be
overloaded
some_class(Args...) = delete;
So here comes the question: I feel that I am wrong that I assume that some_class<> should be deduced to the void specialization... I just don't know why. Can please someone explain why some_class<> (ie: empty argument list) is different from some_class<void>? (A few lines from the standard will do :) )
https://ideone.com/o6u0D6
void is a type like any other (an incomplete type, to be precise). This means it can be used as a template argument for type template parameters normally. Taking your class template, these are all perfectly valid, and distinct, instantiations:
some_class<void>
some_class<void, void>
some_class<void, void, void>
some_class<void, char, void>
In the first case, the parameter pack Args has one element: void. In the second case, it has two elements: void and void. And so on.
This is quite different from the case some_class<>, in which case the parameter pack has zero elements. You can easily demonstrate this using sizeof...:
template <class... Pack>
struct Sizer
{
static constexpr size_t size = sizeof...(Pack);
};
int main()
{
std::cout << Sizer<>::size << ' ' << Sizer<void>::size << ' ' << Sizer<void, void>::size << std::endl;
}
This will output:
0 1 2
[Live example]
I can't really think of a relevant part of the standard to quote. Perhaps this (C++11 [temp.variadic] 14.5.3/1):
A template parameter pack is a template parameter that accepts zero or more template arguments. [ Example:
template<class ... Types> struct Tuple { };
Tuple<> t0; // Types contains no arguments
Tuple<int> t1; // Types contains one argument: int
Tuple<int, float> t2; // Types contains two arguments: int and float
Tuple<0> error; // error: 0 is not a type
—end example ]

SFINAE expression fails to compile with clang

This looks like an issue in clang (I've already opened a bug here), but I'd like to be sure that I'm not doing a mistake.
Consider the following code:
#include <type_traits>
#include <cstddef>
template<std::size_t N, std::size_t M, std::enable_if_t<not (N>M)>* = nullptr> // (1)
struct S: public S<N+1, M> { };
template<std::size_t N>
struct S<N, N> { };
int main() {
S<0, 1> c{};
}
It fails to compile with the following error:
8 : error: non-type template argument specializes a template parameter with dependent type 'std::enable_if_t M)> *' (aka 'typename enable_if M), void>::type *')
struct S { };
The same code works as expected using the following line instead of (1):
template<std::size_t N, std::size_t M, typename = std::enable_if_t<not (N>M)>>
The SFINAE expression is almost the same. It is based on a specialization of std::enable_if_t and I would expect the same result (success or failure) for both of the examples.
Are my expectations wrong?
Note that GCC works fine in either cases.
I think this is a gcc bug actually, as a result of [temp.class.spec]:
The type of a template parameter corresponding to a specialized
non-type argument shall not be dependent on a parameter of the
specialization. [ Example:
template <class T, T t> struct C {};
template <class T> struct C<T, 1>; // error
template< int X, int (*array_ptr)[X] > class A {};
int array[5];
template< int X > class A<X,&array> { }; // error
—end example ]
In your example, the type of the 3rd template parameter is dependent on a parameter. When you swap it to typename = std::enable_if_t<...>, then this rule no longer applies.
Note: is there any reason to use SFINAE here anyway, as opposed to static_assert-ing?

C++11 Check two sets of variadic template arguments match

This question relates to an earlier one I asked regarding implementing something akin to Qt's signal/slots in C++11.
Consider the following (very simplified signal dispatcher, that in this example does nothing of any use, it's just to demonstrate the pattern/problem):
template< typename... TYPES >
class Signal
{
public:
Signal() = default;
~Signal() = default;
template< typename... PARAMETERS >
void broadcast( PARAMETERS &&... p )
{
// static_assert to confirm PARAMETERS can map to TYPES
}
};
This works well enough, but there's some unwanted type conversion going on in practice. e.g.;
// acceptable use.
Signal< int, unsigned, float, char >().broadcast( 1, 2u, 0.f, 'a' );
// should fail compilation, first parameter is a float, 4th is an int.
Signal< int, unsigned, float, char >().broadcast( 0.f, 0, 0.f, 0 );
// acceptable use, first parameter is const, but it's convertible.
const int i = 3;
Signal< int, unsigned, float, char >().broadcast( i, 2u, 0.f, 'a');
// acceptable use, first parameter is const &, but it's convertible.
const int & j = i;
Signal< int, unsigned, float, char >().broadcast( j, 2u, 0.f, 'a');
There should be no silent float to int conversion. Conversion of const/const & in this instance should be possible (the format of TYPES should not have const or & as all data should be passed by value).
I'd like to prevent compilation where such unwanted type conversion happens. I thought to wrap up both TYPES and PARAMETERS in tuples, iterate over the tuple and confirm that each type in a given tuple parameter index matches (including using std::decay), but then I couldn't see a way to do that at compile time so that it could go in a static_assert.
For reference, compilers of choice are clang (latest on OS X 7.3 (clang-703.0.31)) and vc14.
Is what I want to do possible and, if so, can anyone offer any pointers?
Using (once again) the all_true bool pack trick from Columbo:
template <bool...> struct bool_pack;
template <bool... v>
using all_true = std::is_same<bool_pack<true, v...>, bool_pack<v..., true>>;
template <class... Args>
struct Signal {
template <class... Dargs, class = typename std::enable_if<all_true<
std::is_same<Args, typename std::decay<Dargs>::type>{}...
>{}>::type>
void broadcast(Dargs &&...) {}
};
This SFINAE's away the function if the parameters don't match exactly.
Here is a metaprogram I quickly came up with. It is a bit coarse, but can be implemented in a more better way. You should probably use the decayed type (std::decay) in the metaprogram to get correct result.
#include <iostream>
#include <type_traits>
template <typename... T> struct param_pack {};
template <typename, typename> struct is_all_same_impl;
template <>
struct is_all_same_impl<param_pack<>, param_pack<>>
{
static bool const value = true;
};
template <typename T, typename S, typename... Rest, typename... SRest>
struct is_all_same_impl<param_pack<T, Rest...>, param_pack<S, SRest...>>
{
static bool const value = false;
};
template <typename T, typename... Rest, typename... SRest>
struct is_all_same_impl<param_pack<T, Rest...>, param_pack<T, SRest...>>
{
static bool const value = is_all_same_impl<param_pack<Rest...>, param_pack<SRest...>>::value;
};
template <typename, typename>
struct is_all_same;
template <typename... FSet, typename... SSet>
struct is_all_same<param_pack<FSet...>, param_pack<SSet...>>: is_all_same_impl<param_pack<FSet...>, param_pack<SSet...>> {};
int main() {
std::cout << is_all_same<param_pack<int, char, float>, param_pack<int, char, int>>::value << std::endl;
return 0;
}
UPDATE :: More simpler version
template <typename... T> struct param_pack {};
int main() {
std::cout << std::is_same<param_pack<int, float, int>, param_pack<int,float,int>>::value << std::endl;
return 0;
}
So you can do something like:
static_assert( is_same<param_pack<Args...>, param_pack<std::decay_t<Dargs>...>>::value, "Parameters do not sufficiently match." );

Why constexpr data members are not implicitly static?

if you do this:
constexpr int LEN = 100;
LEN variable defined as const without need of typing const keyword.
It also have static storage, without need to type static keyword.
From the other hand, if we do same in class:
struct A{
constexpr static int SIZE = 100;
};
SIZE is still defined as const without need of typing const keyword,
However SIZE is not static data member.
You need to type static explicitly. If you don't there will be compilation error.
Question is:
What is the reason of need to explicitly type static?
static doesn't have same signification in both context :
for LEN, static means "only available in this compilation unit", so only internal linkage. It's a storage specifier
for A::SIZE, static means "it's a class member", so not bound to specific instances
constexpr in class context can refer to instance or class member or function, so compiler can't determine at your place if it's static or not, ie bound or not to a specific instance. It's same reasoning as const specifier. But, as you can imagine, it's a non-sense to have a non-static constexpr member, so it's forbidden. Example :
class A
{
int a;
constexpr A(int value): a(value) {}
// constexpr bound to a specific instance
constexpr int getDouble() const
{ return a*2; }
// constexpr not bound to a specific instance
static constexpr int getDouble(int b)
{ return b*2; }
}
constexpr in global context refers to something which will be calculated at compile time (or, for function, if not possible to calculate at compile time, which will be inlined), so no need of external linkage and so, comparable behavior as a static global variable or function (only comparable because, with compile time calculation or inlining, you also don't need internal linkage)
constexpr int a = 5; // Will be replace everywhere by value
/* If b is constexpr, calcul are done at compile time and result will be used
* else double is inlined, so no need of linkage at all
*/
constexpr int getDouble(int b)
{ return b * 2; }
constexpr should not imply static, because having constexpr
without static makes sense. Consider:
#include <iostream>
struct Dim
{
constexpr Dim(int a,int b) : a(a), b(b) {}
constexpr int Prod() const { return a*b; }
int a,b;
};
int main()
{
constexpr Dim sz(3,4);
int arr[ sz.Prod() ];
std::cout << sizeof(arr) << std::endl;
}
It should also not imply static outside of class definition
since static there means 'local to translation unit' and constexpr
does not require that.
I think you are confused about what static means at global scope, and your question is based on that misunderstanding.
LEN variable defined as const without need of typing const keyword.
Of course constexpr implies const, that shouldn't be surprising.
It also have static storage, without need to type static keyword.
N.B. a global variable always has static storage, because its lifetime is global. Adding the static keyword does not change that, what it does is give it internal linkage meaning it is not accessible by name outside the current translation unit.
That's the same rule for constexpr and const on global variables: a namespace-scope const variable implicitly has internal linkage (which is one of the many meanings of "static").
But a class-scope const variable does not have internal linkage, even if you add static to it. Marking a variable static means something completely different at namespace-scope and class-scope. It doesn't make sense to automatically add static to class members marked const or constexpr because that would mean something completely different than it does to variables at namespace-scope.
So constexpr implies const (obviously), and at namespace scope const implies internal linkage.
At class scope constexpr still implies const, but that doesn't have any effect on whether a member variable is a "class variable" or an "instance variable".

Template type deduction problem

I've got a variant class. It has a pair of constructors:
/// Construct and fill.
template <typename T>
inline
variant (const T& t)
{
YYASSERT (sizeof (T) <= S);
new (buffer.raw) T(t);
}
template <typename T>
inline
variant (T&& t)
{
YYASSERT (sizeof (T) <= S);
new (buffer.raw) T(std::move(t));
}
Now I've called those constructors in this code:
parser::symbol_type
parser::make_IDENTIFIER (const Wide::ParsedFile::Identifier*& v)
{
return symbol_type (token::IDENTIFIER, v);
}
symbol_type takes a variant as it's second argument in this specific constructor, and v is being implicitly converted.
However, MSVC will try to use the rvalue reference constructor instead of using the other constructor, resulting in a compilation error when it attempts to new a reference. Why is that, and how can I make it stop?
You generally should not overload a templated T&& function. You should instead have the single function which forwards:
template <typename T>
inline
variant (T&& t)
{
typedef typename std::remove_reference<T>::type Tr;
YYASSERT (sizeof (Tr) <= S);
new (buffer.raw) Tr(std::forward<T>(t));
}
This has the functionality of your two overloads, while avoiding the problem of picking the wrong one.
I believe (not positive) that these are the two variants in your overload set:
varaint<const Wide::ParsedFile::Identifier*>(const Wide::ParsedFile::Identifier*const&)
varaint<const Wide::ParsedFile::Identifier*&>(const Wide::ParsedFile::Identifier*&)
And the second one wins because it is more specialized than the first (I'm making an educated guess, I'm not 100% positive).
The second template would be a better match, because the const specifiers are in different places in your function and in the first constructor.
In the first overload you will have T being deduced as
const Wide::ParsedFile::Identifier*
And then creating a const reference to that type. That adds an extra const.

Resources