why can't I pass an l-value to a template class constructor that uses universal references? - c++17

I have a templated class MyClass<T> that takes some iterable containing ints (e.g. T = std::vector<int>) in its constructor and does something with it.
I would like to be able to pass the iterable as either a temporary object (e.g. MyClass(std::vector<int>{3,6,9}) or similar r-value argument) or from a named variable (resulting in an l-value as the constructor argument).
I would like to use C++17 template class inference (i.e. write MyClass(...), not MyClass<std::vector<int>>(...)).
I thought that I could declare the constructor parameter as MyClass(T && vec) (a "universal reference") to take either an l-value or an r-value (just like I can with functions), but it gives an error. It seems like T is always inferred as std::vector<int> and never std::vector<int>& with classes, whereas functions infer std::vector<int>& when the argument is an l-value.
How exactly are the rules for template constructor inference and template function inference different? Can I avoid having to use a wrapper function (e.g. myFunction(T&&vec) { return MyClass<T>(std::forward<T>(vec)); }) just for the sake of template inference?
Run the code below on Godbolt:
#include <iostream>
#include <utility>
#include <vector>
template <typename T>
using BeginType = decltype(std::declval<T>().begin());
template <typename T>
struct MyClass {
BeginType<T> begin;
BeginType<T> end;
MyClass(T && vec) {
begin = std::forward<T>(vec).begin();
end = std::forward<T>(vec).end();
}
int sum() {
int sum = 0;
for (auto it = begin; it != end; ++it) sum += *it;
return sum;
}
};
template <typename T>
MyClass<T> myFunction(T && vec) {
return MyClass<T>(std::forward<T>(vec));
}
int main() {
std::vector<int> x{1, 2, 3};
std::vector<int> y{2, 4, 6};
// Warmup: Passing r-values works fine
std::cout << MyClass(std::vector<int>{3, 6, 9}).sum() << std::endl; // works fine: T is std::vector<int>
std::cout << MyClass(std::move(y)).sum() << std::endl; // works fine: T is std::vector<int>
// Unexpected: Passing l-values doesn't work
// std::cout << MyClass(x).sum() << std::endl; // error: cannot bind rvalue reference of type 'std::vector<int>&&' to lvalue of type 'std::vector<int>'
// Compare: Passing l-values to function works fine
std::cout << myFunction(x).sum() << std::endl; // works fine: T is std::vector<int>&
}

Add a user-defined deduction guide after the class definition:
template <typename T>
struct MyClass {
// same as in question
};
template <typename TT> MyClass(TT && vec) -> MyClass<TT>;
See also How to write a constructor for a template class using universal reference arguments in C++

Related

Why do I get an implicit move constructor in a class with a user-defined destructor

I am confused with some aspects of the implicit move constructor.
My understanding is that the implicitly-declared move constructor are provided by the compiler for a class iff there are no user-declared copy constructors, no copy assignment operators, no move assignment operators and no destructors.
This is the case with 'Heavy' in my example. Which behaves as expected (data is moved).
'HeavyWithDestructor' would not qualify for a implicitly-declared move constructor, because it has a destructor, but I can "std::move" it. Sort of, it is a copy (see the data pointer).
This looks to me like a trivial move constructor, in the sense that it performs the same actions as the trivial copy constructor (as if by std::memmove).
But if I don't have the conditions for the creation of a implicit move constructor in the first place, how can it be a trivial move constructor. Further more, 'std::is_trivially_move_constructible_v' indicates this is not a trivial move constructor.
#include <iostream>
#include <vector>
#include <type_traits>
using namespace std;
constexpr int largeNumber = 10000000;
#define OUT(...) std::cout << #__VA_ARGS__ << " : " << __VA_ARGS__ << '\n'
// Consistent with an implicit 'move' constructor.
class Heavy
{
vector<int> v_;
public:
Heavy() : v_(vector<int>(largeNumber)) {}
int* getDatap() { return v_.data(); }
};
// Not consistent with an implicit 'move' constructor. (Because has a destructor)
class HeavyWithDestructor
{
vector<int> v_;
public:
HeavyWithDestructor() : v_(vector<int>(largeNumber)) {}
~HeavyWithDestructor(){}
int* getDatap() { return v_.data(); }
};
int main()
{
cout << "Moving a heavy object" << endl;
OUT(std::is_move_constructible_v<Heavy>);
OUT(std::is_trivially_move_constructible_v<Heavy>);
Heavy originalHeavy;
cout << "Data* in original() -> " << originalHeavy.getDatap() << endl;
Heavy finalHeavy = move(originalHeavy);
cout << "Data* in main() -> " << finalHeavy.getDatap() << endl << endl;
cout << "Moving a heavy object with a destructor" << endl;
OUT(std::is_move_constructible_v<HeavyWithDestructor>);
OUT(std::is_trivially_move_constructible_v<HeavyWithDestructor>);
HeavyWithDestructor originalWoDestructor;
cout << "Data* in original() -> " << originalWoDestructor.getDatap() << endl;
HeavyWithDestructor finalWoDestructor = move(originalWoDestructor);
cout << "Data* in main() -> " << finalWoDestructor.getDatap() << endl;
return 0;
}
I get the following output: I can confirm I am moving 'Heavy' cause the pointers to the vector data point to the same location. I can also confirm that 'HeavyWithDestructor' is copying, not moving the data.
Moving a heavy object
std::is_move_constructible_v<Heavy> : 1
std::is_trivially_move_constructible_v<Heavy> : 0
Data* in original() -> 000001E3FB193080
Data* in main() -> 000001E3FB193080
Moving a heavy object with a destructor
std::is_move_constructible_v<HeavyWithDestructor> : 1
std::is_trivially_move_constructible_v<HeavyWithDestructor> : 0
Data* in original() -> 000001E3FD7C6080
Data* in main() -> 000001E38000A080
What is this constructor that the compiler is declaring for 'HeavyWithDestructor'?. If this constructor is not moving the data, why can I still use std::move on it?
If I try harder to make the compiler NOT declare a move constructor for me by defining a copy constructor, then I cannot use the std::move. I get compilation errors. This is what I would expect. From this, I gather the constructor I am getting is not a copy constructor. From where I initially suspected this is a trivial move constructor (that behaves as in std::memmove), but I have indications that is not right either. So what is this?
I am using vs2019 c++17 as a compiler.
HeavyWithDestructor is a typical C++03 type: copyable but not movable (what’s “movable”?). As such, for compatibility, it is copied whenever a move is attempted. The technical reason for this is that const HeavyWithDestructor& can bind to an rvalue; the moral reason is that std::move, as always, grants permission to move something but does not require it (or do so itself).
(Your experiment with a copy constructor is not detailed enough to reproduce, but might have involved HeavyWithDestructor(HeavyWithDestructor&) that is still considered a copy constructor but cannot serve as a move constructor.)

C++ Templated class function that can detect std::vector

If I have a templated class, I can do the following to detect if a vector was passed:
template<typename T> struct is_vector { static const bool value=false; };
template<typename T> struct is_vector<std::vector<T>> { static const bool value=true; };
template<class T>
class Parser {
public:
Parser() {}
void parse(T obj) {
if (is_vector<T>::value) {
std::cout << "vector\n";
//obj.push_back(T {});
}
else {
std::cout << "not vector\n";
}
}
};
int main() {
Parser<int> p1;
p1.parse(123);
Parser<std::vector<int>> p2;
p2.parse({ 1, 2, 3});
return 0;
}
Output:
not vector
vector
I can detect a vector, yet the compiler complains when I uncomment the push_back call:
main.cpp: In instantiation of ‘void Parser<T>::parse(T) [with T = int]’:
main.cpp:26:14: required from here
main.cpp:15:17: error: request for member ‘push_back’ in ‘obj’, which is of non-class type ‘int’
obj.push_back(T {});
~~~~^~~~~~~~~
Obviously, an int does not have a push_back function, but the vector does. The is_vector call is evaluated at runtime, but the push_back is caught at compile time.
With partial template specialization, I can do what I want:
template<typename T>
void parse(T obj) {
std::cout << "not vector: " << obj << "\n";
}
template<typename T>
void parse(std::vector<T> obj) {
std::cout << "is vector\n";
for (auto i : obj) std::cout << i << " ";
obj.push_back(T {});
std::cout << "\n";
for (auto i : obj) std::cout << i << " ";
std::cout << "\n";
}
int main() {
parse(1);
parse('a');
parse(std::vector<int> { 1, 2, 3 });
return 0;
}
Output:
not vector: 1
not vector: a
is vector
1 2 3
1 2 3 0
So, how can I combine these 2 ideas, either at compile-time or at runtime? That is, have a templated class with a function that can handle vectors and non-vectors?
What you're looking for is a new feature in C++17, if constexpr. It's the same as a regular if, except that the condition is evaluated at compile time, and when instantiating the branch(es) will discard the non-taken branch at compile time. The discarded branch does not need to well-formed. So, for your example:
template<class T>
class Parser {
public:
Parser() {}
void parse(T obj) {
if constexpr (is_vector<T>::value) {
std::cout << "vector\n";
obj.push_back(T {});
}
else {
std::cout << "not vector\n";
}
}
};
See Difference between if constexpr vs if for some more talk on the differences. You can also read the cppreference page on if statements to get a detailed overview of some of the nitty-gritty details.

Storing multiple types into class member container

I was reading this Q/A here and as my question is similar but different I would like to know how to do the following:
Let's say I have a basic non template non inherited class called Storage.
class Storage {};
I would like for this class to have a single container (unordered multimap) is where I'm leaning towards... That will hold a std::string for a name id to a variable type T. The class itself will not be template. However a member function to add in elements would be. A member function to add might look like this:
template<T>
void addElement( const std::string& name, T& t );
This function will then populate the unorderd multimap. However each time this function is called each type could be different. So my map would look something like:
"Hotdogs", 8 // here 8 is int
"Price", 4.85f // here 4.8f is float.
How would I declare such an unorderd multimap using templates, variadic parameters, maybe even tuple, any or variant... without the class itself being a template? I prefer not to use boost or other libraries other than the standard.
I tried something like this:
class Storage {
private:
template<class T>
typedef std::unorderd_multimap<std::string, T> DataTypes;
template<class... T>
typedef std::unordered_multimap<std::vector<std::string>, std::tuple<T...>> DataTypes;
};
But I can not seem to get the typedefs correct so that I can declare them like this:
{
DataTypes mDataTypes;
}
You tagged C++17, so you could use std::any (or std::variant if the T type can be a limited and know set of types`).
To store the values is simple.
#include <any>
#include <unordered_map>
class Storage
{
private:
using DataTypes = std::unordered_multimap<std::string, std::any>;
DataTypes mDataTypes;
public:
template <typename T>
void addElement (std::string const & name, T && t)
{ mDataTypes.emplace(name, std::forward<T>(t)); }
};
int main()
{
Storage s;
s.addElement("Hotdogs", 8);
s.addElement("Price", 4.85f);
// but how extract the values ?
}
But the problem is that now you have a element with "Hotdogs" and "Price" keys in the map, but you have no info about the type of the value.
So you have to save, in some way, a info about the type of th value (transform the value in a std::pair with some id-type and the std::any?) to extract it when you need it.
I've done something along those lines, the actual solution is very specific to your problem.
That being said, I'm doing this on a vector, but the principle applies to maps, too.
If you're not building an API and hence know all classes that will be involved you could use std::variant something along the lines of this:
#include <variant>
#include <vector>
#include <iostream>
struct ex1 {};
struct ex2 {};
using storage_t = std::variant<ex1, ex2>;
struct unspecific_operation {
void operator()(ex1 arg) { std::cout << "got ex1\n";}
void operator()(ex2 arg) { std::cout << "got ex2\n";}
};
int main() {
auto storage = std::vector<storage_t>{};
storage.push_back(ex1{});
storage.push_back(ex2{});
auto op = unspecific_operation{};
for(const auto& content : storage) {
std::visit(op, content);
}
return 0;
}
which will output:
got ex1
got ex2
If I remember correctly, using std::any will enable RTTI, which can get quite expensive; might be wrong tho.
If you provide more specifics about what you actually want to do with it, I can give you a more specific solution.
for an example with the unordered map:
#include <variant>
#include <unordered_map>
#include <string>
#include <iostream>
struct ex1 {};
struct ex2 {};
using storage_t = std::variant<ex1, ex2>;
struct unspecific_operation {
void operator()(ex1 arg) { std::cout << "got ex1\n";}
void operator()(ex2 arg) { std::cout << "got ex2\n";}
};
class Storage {
private:
using map_t = std::unordered_multimap<std::string, storage_t>;
map_t data;
public:
Storage() : data{map_t{}}
{}
void addElement(std::string name, storage_t elem) {
data.insert(std::make_pair(name, elem));
}
void doSomething() {
auto op = unspecific_operation{};
for(const auto& content : data) {
std::visit(op, content.second);
}
}
};
int main() {
auto storage = Storage{};
storage.addElement("elem1", ex1{});
storage.addElement("elem2", ex2{});
storage.addElement("elem3", ex1{});
storage.doSomething();
return 0;
}

How to discover lock declaration instruction in llvm?

I'm new to llvm , and was trying to find lock declaration statement and then do some instrumention work,the code like this:
#include <iostream>
#include <thread>
#include <mutex>
using namespace std;
int share = 42;
mutex m;
void f()
{
m.lock();
--share;
cout << "function f -> share: " << share << '\n';
m.unlock();
}
int main()
{
thread thf{f};
thf.join();
return 0;
}
I want to find the lock declaration instruction eg:
mutex m;
the llvm instrumention pass like this:
struct SkeletonPass : public FunctionPass {
static char ID;
SkeletonPass() : FunctionPass(ID) {}
virtual bool runOnFunction(Function &F) {
// Get the function to call from our runtime library.
LLVMContext &Ctx = F.getContext();
Constant *logFunc = F.getParent()->getOrInsertFunction(
"logop", Type::getVoidTy(Ctx), Type::getInt32Ty(Ctx), NULL
);
for (auto &B : F) {
for (auto &I : B) {
***if ((&I) is lock declaration instruction)*** {
// Insert something *after* `op`.
IRBuilder<> builder(op);
builder.SetInsertPoint(&B, ++builder.GetInsertPoint());
// Insert a call to function.
builder.CreateCall(logFunc, ConstantInt::get(Type::getInt32Ty(Ctx), 2));
return true;
}
}
}
In short, could you please tell me how to discover lock declaration instruction, thanks!
The declaration would appear as a global, so you should write a module pass to find it, not a function pass. It should appear as something like:
#m = global %mutex zeroinitializer
In fact, using the demo at http://ellcc.org/demo/index.cgi to try this, you can indeed see that:
...
%"class.std::__1::mutex" = type { %struct.pthread_mutex_t }
%struct.pthread_mutex_t = type { %union.anon }
%union.anon = type { [5 x i8*] }
...
#m = global %"class.std::__1::mutex" zeroinitializer, align 8
You can use LLVM's CppBackend to compile your code. This would produce a C++ code that makes up the source. You can then easily find out how mutex m; definition is constructed via LLVM API.
Run clang -march=cpp foo.cpp to use CppBackend. Alternatively, you can use this demo page to compile your code online.

boost python overload operator ()

I would like to bind the operator() using Boost::Python but I don't really see how to do this. Consider the example:
C++:
class Queuer
{
public:
void Queuer::operator()(const qfc::Queue & iq, const qfc::Message & im) const;
void Queuer::operator()(const qfc::Agent & ia, const qfc::Message & im) const;
// some other overloaded operator() methods
};
So in a Python script, after importing the module I'm using (called qfc), I would like to do:
Python:
>>> queuer = qfc.Queuer()
// instantiating a Message an Agent and a Queue object
>>> queuer(queue,message)
>>> queuer(agent,message)
>>> ...
Would you have any idea on how to do it? maybe with boost::python call<>?
Thank you,
Kevin
When exposing the Queuer class, define a __call__ method for each Queuer::operator() member function. Boost.Python will handle the appropriate dispatching based on types. The only complexity is introduced with pointer-to-member-function syntax, as the caller is required to disambiguate &Queuer::operator().
Additionally, when attempting to pass derived classes in Python to a C++ function with a parameter of the Base class, then some additional information needs to be exposed to Boost.Python:
The base C++ class needs to be exposed with class_. For example, class_<BaseType>("Base").
The derived class needs to explicitly list its base classes when being exposed with bases_. For example, class_<DerivedType, bases<BaseType> >("Derived"). With this information, Boost.Python can do proper casting while dispatching.
Here is a complete example:
#include <iostream>
#include <boost/python.hpp>
// Mockup classes.
struct AgentBase {};
struct MessageBase {};
struct QueueBase {};
struct SpamBase {};
struct Agent: AgentBase {};
struct Message: MessageBase {};
struct Queue: QueueBase {};
struct Spam: SpamBase {};
// Class with overloaded operator().
class Queuer
{
public:
void operator()(const AgentBase&, const MessageBase&) const
{
std::cout << "Queuer::operator() with Agent." << std::endl;
}
void operator()(const QueueBase&, const MessageBase&) const
{
std::cout << "Queuer::operator() with Queue." << std::endl;
}
void operator()(const SpamBase&, const MessageBase&) const
{
std::cout << "Queuer::operator() with Spam." << std::endl;
}
};
/// Depending on the overlaod signatures, helper types may make the
/// code slightly more readable by reducing pointer-to-member-function syntax.
template <typename A1>
struct queuer_overload
{
typedef void (Queuer::*type)(const A1&, const MessageBase&) const;
static type get(type fn) { return fn; }
};
BOOST_PYTHON_MODULE(example)
{
namespace python = boost::python;
// Expose only the base class types. Do not allow the classes to be
// directly initialized in Python.
python::class_<AgentBase >("AgentBase", python::no_init);
python::class_<MessageBase>("MessageBase", python::no_init);
python::class_<QueueBase >("QueueBase", python::no_init);
python::class_<SpamBase >("SpamBase", python::no_init);
// Expose the user types. These classes inerit from their respective
// base classes.
python::class_<Agent, python::bases<AgentBase> >("Agent");
python::class_<Message, python::bases<MessageBase> >("Message");
python::class_<Queue, python::bases<QueueBase> >("Queue");
python::class_<Spam, python::bases<SpamBase> >("Spam");
// Disambiguate via a varaible.
queuer_overload<AgentBase>::type queuer_op_agent = &Queuer::operator();
python::class_<Queuer>("Queuer")
// Disambiguate via a variable.
.def("__call__", queuer_op_agent)
// Disambiguate via a helper type.
.def("__call__", queuer_overload<QueueBase>::get(&Queuer::operator()))
// Disambiguate via explicit cast.
.def("__call__",
static_cast<void (Queuer::*)(const SpamBase&,
const MessageBase&) const>(
&Queuer::operator()))
;
}
And its usage:
>>> import example
>>> queuer = example.Queuer()
>>> queuer(example.Agent(), example.Message())
Queuer::operator() with Agent.
>>> queuer(example.Queue(), example.Message())
Queuer::operator() with Queue.
>>> queuer(example.Spam(), example.Message())
Queuer::operator() with Spam.
Thanks for your help.
Actually I've already tested the static cast solution. In reality, I need to pass a qfc::lqs::Message or qfc::lqs::Agent or qfc::lqs::Spam when invoking queuer(). qfc::lqs::Message for example, as for qfc::lqs::Agent inherit from qfc::Message and qfc::Agent respectively.
So can I "cast" qfc::lqs::Message, qfc::lqs::Agent and qfc::lqs::Spam to qfc::Message, qfc::Agent and qfc::Spam when invoking the operator() so that the signature corresponds to operator() ?
This to avoid the error shown below:
error: invalid static_cast from type '<unresolved overloaded function type>' to type 'void (qfc::lqs::Queuer::*)(const qfc::lqs::Queue&, const qfc::lqs::Message&)const'

Resources