I was experimenting with how std::move and std::forward differs, and I have found that I am not able to use std::forward on class field:
name = std::forward<T>(rhs.name);
below is full example. The error I am getting under gcc 6.3 is:
C:/PROGRA~1/MINGW-~1/X86_64~3.0-P/mingw64/lib/gcc/x86_64-w64-mingw32/6.3.0/include/c++/bits/move.h:89:7: error: static assertion failed: template argument substituting _Tp is an lvalue reference type
static_assert(!std::is_lvalue_reference<_Tp>::value, "template argument"
^~~~~~~~~~~~~
I understand that the cause is probably because T is of type WrongUseOfMove. But I wonder if forwarding only a sub variable is possible. For example I could use passed in rhs parameter and forward its fields to different class variables.
#include <iostream>
#include <string>
#include <vector>
class WrongUseOfMove {
public:
template<typename T>
WrongUseOfMove(T&& rhs)
{
//name = std::move(rhs.name); // Very wrong!!
//name = std::forward<T>(rhs.name); // Does not compile, T is WrongUseOfMove instead decltype(rhs.name);
name = std::forward<decltype(rhs.name)>(rhs.name); // compiles - but is it correct?
std::cout << __PRETTY_FUNCTION__ << "\n";
}
WrongUseOfMove(){}
std::string name;
};
int main()
{
WrongUseOfMove wm;
WrongUseOfMove wm2 = wm;
}
http://coliru.stacked-crooked.com/a/88d8591ee1478a3f
You may use the intuitive way:
name = std::forward<T>(rhs).name;
Demo
Your try:
name = std::forward<decltype(rhs.name)>(rhs.name);
does an unconditional move:
Demo
Related
This question already has answers here:
Is it possible to print a variable's type in standard C++?
(25 answers)
Closed 1 year ago.
I am writing a wrapper for boost numeric_cast with the wrapper function something like:
#include <boost/numeric/conversion/cast.hpp>
#include <stdexcept>
template <typename Source, typename Target>
Target numeric_cast(Source src)
{
try
{
// calling boost numeric_cast here
}
catch(boost::numeric::bad_numeric_cast& e)
{
throw std::runtime_error("numeric_cast failed, fromType: " + Source + " toType: " + Target);
}
}
I am having this error:
error: expected primary-expression before ‘(’ token
throw std::runtime_error("numeric_cast failed ...
^
I think the error is asking to handle Source and Target in the error message. So is there a way to print template typename? I am a beginner in c++, so it maybe a silly question...
You can use typeid(T).name() to get the raw string of the template parameter:
#include <boost/numeric/conversion/cast.hpp>
#include <stdexcept>
#include <typeinfo>
template <typename Source, typename Target>
Target numeric_cast(Source src)
{
try
{
// calling boost numeric_cast here
}
catch(boost::numeric::bad_numeric_cast& e)
{
throw (std::string("numeric_cast failed, fromType: ") +
typeid(Source).name() + " toType: " + typeid(Target).name());
}
}
Demo.
Please note that the string literal "numeric_cast failed, fromType:" should be std::string type to support '+' operator.
First of all you should flip template arguments. Source can be auto-deduced on other hand Target can't. So Target must be explicitly provided and should come first in template parameter list, so Source could be deduced anyway.
Second problem is that string literals can't be added like that (this comes from C). To build complex strings in C++ use std::ostringstream.
To get type name information you can use typeid. Since this name is mangled and you already use boost, you can demagle that names using boost and get nice human readable type name.
Last thing: direct use of std::runtime_error is manifestation of lazy developer. It is a good practice to introduce own exception class for such scenarios.
#include <iostream>
#include <sstream>
#include <boost/numeric/conversion/cast.hpp>
#include <boost/core/demangle.hpp>
#include <typeinfo>
#include <stdexcept>
template<typename T>
std::string typeName()
{
return boost::core::demangle(typeid(T).name());
}
// this is used to bind all exceptions related to local library
class MyLibExceptions : public std::exception
{};
class BadNumericCast : public MyLibExceptions
{
public:
template<typename Target, typename Source>
BadNumericCast(Source arg, Target, const char *extra)
{
std::ostringstream desc;
desc << extra << " from type: '" << typeName<Source>()
<< "' with value: " << arg
<< " to type: '" << typeName<Target>() << '\'';
mDesc = desc.str();
}
const char* what() const noexcept override
{
return mDesc.c_str();
}
private:
std::string mDesc;
};
template <typename Target, typename Source>
Target numeric_cast(Source arg)
{
try
{
return boost::numeric::converter<Target, Source>::convert(arg);
}
catch(boost::numeric::bad_numeric_cast& e)
{
throw BadNumericCast{arg, Target{}, e.what()};
}
}
Live demo
I have a class with static and overloaded member function.
I want to use one them as a custom deleter in a unique_ptr
there are lots of questions on this topic, none of them worked for me.
#include <iostream>
#include <memory>
#include <functional>
class A {
public:
static void release() {
std::cout << "void released\n";
}
static void release(int*i) {
std::cout << *i << " released\n";
}
};
int main()
{
int i = 10;
std::unique_ptr<int, decltype(&A::release(int*))> ptr(&i, &A::release); // compiler error
std::unique_ptr<int, std::function<void(int*)>> ptr(&i, &A::release); // compiler error
return 0;
}
try it out here: https://onlinegdb.com/H14txk3sL
std::unique_ptr<int, void(*)(int*)> ptr(&i, &A::release);
// ~~~~~~~~~~~~^
This way, std::unique_ptr's constructor will expect a specific type of a pointer, which will help the compiler resolve ambiguity.
This:
decltype(&A::release(int*))
is not a valid syntax. In order yo use decltype(e), you'd have to write decltype(&A::release), but this again would raise an ambiguity error, and so it would have to become:
decltype(static_cast<void(*)(int*)>(&A::release))
but that's a long-winded way of saying void(*)(int*).
This:
std::function<void(int*)>
doesn't help in resolving ambiguity, becuase std::functions's constructor is a template as well, which means the compiler again misses a context that would help it to choose one of the overloaded functions.
I am trying to find the type of variable. In stackoverflow it is mentioned that decltype() is used for that purpose. But when I tried to used it is throwing me the error as I mentioned in title.
#include <bits/stdc++.h>
using namespace std;
int main()
{
int x = 4;
cout << decltype(x);
return 0;
}
I expected int but it showing as error. error: expected primary-expression before 'decltype'
Types aren't first class objects. You can't pass a type to a function, and cout << decltype(x) is exactly that, passing a type to a function (though beautified by the operator).
To get an info about the type of a variable, you can
Read the code. If the type of an object is int, don't bother printing it.
Step through your program with a debugger. It shows the type of variables.
Use this (non-standard) function template
template <class T> void printType(const T&)
{
std::cout << __PRETTY_FUNCTION__ << "\n";
}
printType(x);
Use Boost.
#include <boost/type_index.hpp>
std::cout << boost::typeindex::type_id_with_cvr<decltype(x)>().pretty_name() << "\n";
I'm trying to learn some basic C++ 11, using Scott Meyers lecture on youtube called "An Effective C++11/14 Sampler"
https://www.youtube.com/watch?v=BezbcQIuCsY
Using his sample code for std::forward (min 19 in the lecture) I wrote the following code to understand the effect of std::forward
#include "stdafx.h"
#include <string>
#include <utility>
class A
{
public:
void Foo(std::string&& s)
{
std::string s2 = std::forward<std::string>(s);
}
};
int _tmain(int argc, _TCHAR* argv[])
{
A a;
std::string s3 = "Hello World";
a.Foo(s3);
a.Foo("Hello World");
return 0;
}
Surprisingly it doesn't compile, a.Foo(s3) can't implicitly cast from lvalue to rvalue. So I changed a.Foo(s3); to a.Foo(std::move(s3)); Now it compiles.
However on both calls to Foo std::forward<std::string>(s); resolved to an rvalue and a Move operation occurred (s was reset to "" as its buffer was pilfered).
So I really don't understand what good is std::forward and when it does apply. What am I missing here?
Calling std::forward<> when template argument deduction / reference collapsing isn't involved doesn't make sense.
The point of forwarding references (which Scott Meyers used to call "universal references") is that, depending on the value category of what you're receiving, you can forward that value category as well.
But here, you're not confused at all as to what's the value category, it's static.
Here is a context that has template argument deduction:
template<typename T>
void f(T&& t) // T is to be deduced, && might be collapsed
{
g(std::forward<T>(t)); // will keep the category value
}
f(std::string{"hey"}); // T inferred std::string&&, so the parameter type is `std::string&& &&`, which is collapsed to `std::string &&`.
You need a forwarding reference:
#include <string>
#include <utility>
class A
{
public:
template <typename String>
void Foo(String&& s)
{
std::string s2 = std::forward<String>(s);
}
};
int main()
{
A a;
std::string s3 = "Hello World";
a.Foo(s3);
a.Foo("Hello World");
return 0;
}
live example
In the ideal case, I would like to use the ClassVariant in the following way:
// store & retrieve int
map<string, ClassVariant> mapValues;
mapValues["int_fieldX"] = ClassVariant(20);
int fieldX = (mapValues["int_fieldX"])();
// Or int fieldX = (mapValues["int_fieldX"]);
However, I can ONLY implement the following code that requires the retrieving statement to feed the type info as follows:
int fieldB = (mapValuesTwo["int_fieldB"])(int(0));
As you can see int(0) is provided as type info. Is there a way that I can remove this limitation. So that the type info is NOT needed.
#include <iostream>
#include <iomanip>
#include <string>
#include <map>
#include <boost/variant.hpp>
using namespace std;
typedef boost::variant<int, double, string> VarIntDoubleString;
class ClassVariant
{
public:
ClassVariant() : m_value(int(0)) {}
ClassVariant(VarIntDoubleString _val) : m_value(_val) {}
template<typename T>
T operator()(const T&) const
{
return boost::get<T>(m_value);
}
private:
VarIntDoubleString m_value;
};
int main(void)
{
map<string, ClassVariant> mapValuesTwo;
// store & retrieve int
mapValuesTwo["int_fieldB"] = ClassVariant(20);
int fieldB = (mapValuesTwo["int_fieldB"])(int(0));
cout << "fieldB: " << fieldB << endl;
// store & retrieve string
mapValuesTwo["int_fieldD"] = ClassVariant("Hello world");
string fieldD = (mapValuesTwo["int_fieldD"])(string(""));
cout << "fieldD: " << fieldD << endl;
}
// Output
fieldB: 20
fieldD: Hello world
You can't do this, template argument deduction works only on the parameters, not on the return value of a function. Your best choice is to ditch operator() for a normal function like get<T>(). I can't point to the relevant line in the standard though, too obscure for me.
Note: if such a thing was possible, my guess would be that boost::variant would already have a get function where specifying T is not requried.
EDIT: see this question
You SHOULD use boost::variant together with visitor to access the value in it. see here