Why do std::pair and std::tuple behave differently when using std::scoped_allocator_adaptor'ed allocators for the containers?
std::pair fails:
std::vector<std::pair<std::string, std::string>,
std::scoped_allocator_adaptor<std::allocator<std::pair<std::string, std::string>>>> v;
v.push_back(std::make_pair( "one", "two" )); // <--- does not compile
while std::tuple works
std::vector<std::tuple<std::string, std::string>,
std::scoped_allocator_adaptor<std::allocator<std::tuple<std::string, std::string>>>> v2;
v2.push_back(std::make_tuple("one", "two")); // <- no problem
Is this related to the fact that std::tuple has uses_allocator while std_pair does not?
Related
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
The following code is valid in C++11 and can be used to convert to a const version of the underlying pointer type.
std::unique_ptr<int> a = std::unique_ptr<int>(new int(10));
std::unique_ptr<const int> b = std::move(a);
Is it possible to achieve the same thing when using a unique_ptr with a custom deleter?
std::unique_ptr<int, std::function<void(int*)>> a = std::unique_ptr<int, std::function<void(int*)>>(new int(10), [](int*){});
std::unique_ptr<const int, ???> b = std::move(a);
As I would expect (due to the different types) I get compiler errors whether I use int* or const int* for the deleter argument in the const definition.
Some context: I'm trying to typedef a drop-in replacement unique_ptr signature that works with a custom allocator and can be used wherever unique_ptr was used e.g.
template <typename T> using CustomUniquePtr = std::unique_ptr<T, std::function<void(???)>>;
I have a std::tuple (or a boost fusion tuple) whose elements cannot be trivially constructed (for example references) and I want to iterate over the types but not the values of the elements.
In this example I have a (general) tuple type and I want to generate a vector with (runtime) type information. The example below works if all the types in the sequence are trivially default constructed but not in general.
In summary, I want a function that transform: std::tuple<...> -> std::vector<std::type_index>
#include <boost/fusion/adapted/std_tuple.hpp>
#include <boost/fusion/algorithm/iteration/for_each.hpp>
#include <typeindex>
#include<vector>
using tuple_type = std::tuple<std::string&, int>;
int main(){
std::vector<std::type_index> types;
boost::fusion::for_each(
tuple_type{}, // fails because of std::string&
[&types](auto& e){types.push_back(typeid(e));}
);
}
The problem is that I have to generate runtime information from non runtime information and I can't figure out how to mix the fusion functions (http://www.boost.org/doc/libs/1_59_0/libs/fusion/doc/html/fusion/algorithm/iteration/functions.html) and the metafunctions (http://www.boost.org/doc/libs/1_41_0/libs/fusion/doc/html/fusion/algorithm/iteration/metafunctions.html).
I tried with boost::fusion::accumulate and boost::fold but the situation is always the same, at some point I have to generate a runtime element in order to apply the algorithm.
EDIT: I solved the original problem (std::tuple<...> -> std::vector<std::type_index>). I can't imagine another context at the moment but maybe the fundamental question still stands.
I did it by using a trick involving expanding a parameter pack over the typeid function in the constructor of std::vector (or std::array).
template<class... Args>
std::array<std::type_index, sizeof...(Args)> const& types_info<std::tuple<Args...>>::value{typeid(Args)...};
The complete code is this (note that I also decided to use std::array).
#include <typeindex>
#include<array>
#include<iostream>
template<class T>
struct types_info;
template<class... Args>
struct types_info<std::tuple<Args...>>{
static std::array<std::type_index, sizeof...(Args)> const& value;//{typeid(Args)...};
};
template<class... Args>
std::array<std::type_index, sizeof...(Args)> const& types_info<std::tuple<Args...>>::value{typeid(Args)...};
// vvv works only in C++1z
template<template<typename...> typename T, class... Args> // non tuples types as well
struct types_info<T<Args...>> : types_info<std::tuple<Args...>>{};
using tuple_type = std::tuple<std::string&, int>;
int main(){
std::vector<std::type_index> types;
std::cout << types_info<tuple_type>::value.size() << std::endl;
std::cout << types_info<std::map<int, std::string>>::value.size() << std::endl;
}
I'm experimenting with C++11 (I've used old C++ so far) and I wrote the following code:
#include <iostream>
#include <vector>
#include <type_traits>
using namespace std;
constexpr bool all_true(){
return true;
}
template <typename Head, typename... Tail>
constexpr bool all_true(Head head, Tail... tail){
static_assert( is_convertible<bool, Head>::value, "all_true arguments must be convertible to bool!");
return static_cast<bool>(head) && all_true(tail...);
}
template<typename T, typename... Args>
void print_as(Args... args){
static_assert( all_true(is_convertible<T,Args>::value...), "all arguments must be convertible to the specified type!");
vector<T> v {static_cast<T>(args)...};
for(T i : v) cout << i << endl;
}
int main(){
print_as<bool>(1, 2, 0, 4.1);
}
The code compiles and runs as expected (I used gcc 4.6). I would like to aks the following questions:
I initialized a std::vector with an expanded parameter pack ( vector v {static_cast(args)...}; ). Is this correct C++11? I haven't found this feature explained anywhere.
I don't like too much the declaration of all_true because I know the type but I use templates. Is it possible to use something similar to the following?
constexpr bool all_true(bool head, bool... tail){...} // This code doesn't compile
Thanks!
Yes, it is possible to use pack expansions inside initialiser lists. C++11 [temp.variadic]§4 allows this:
... Pack expansions can occur in the following contexts:
...
In an initializer-list (8.5); the pattern is an initializer-clause.
No, there's no way to make a non-template typesafe variadic function. What you have is OK. There was a question about this recently.
How can I make static_assert for specific type constraint?
Currently I want to make my template only for unsigned int type, but not signed int type. Or, just only for integral type, or specific type names. static_assert(sizeof(int)) offers only size based assertion, and I don't know how to perform any extra checks.
I am using Clang with its libc++ in Xcode 4.6.2. Here's current compiler information on command-line.
Apple LLVM version 4.2 (clang-425.0.28) (based on LLVM 3.2svn)
Target: x86_64-apple-darwin12.3.0
Thread model: posix
That's not really what static_assert is for, but you can do it like this:
template<typename T>
struct Type
{
static_assert(std::is_same<T, unsigned int>::value, "bad T");
};
Or, if you just want T to be an unsigned integral type of some sort (not specifically unsigned int):
template<typename T>
struct Type
{
static_assert(std::is_unsigned<T>::value, "bad T");
};
To check for all integral types, the following can be used:
#include <type_traits>
// [...]
static_assert(std::is_integral<T>::value, "The type T must be an integral type.");
// [...]
Here's a scaffold:
#include <type_traits>
template<typename TNum>
struct WrapNumber
{
static_assert(std::is_unsigned<TNum>::value, "Requires unsigned type");
TNum num;
};
WrapNumber<unsigned int> wui;
WrapNumber<int> wi;