codereview would not allow hypothetical code, so I am posting here instead. Given this code:
#include <string>
struct foo {
std::string a, b;
foo (const std::string& a, const std::string& b) : a(a), b(b) { }
};
template <typename T> void bar (const T&) { }
template <typename T> void bar (T&&) { }
void execute (const foo& f) {
// etc...
bar(f.a);
// etc...
bar(f.b);
// etc...
bar(f);
// etc...
}
void execute (foo&& f) {
// etc...
bar(std::move(f.a));
// etc...
bar(std::move(f.b));
// etc...
bar(std::move(f));
// etc...
}
int main() {}
I want to write execute_helper to handle both execute overloads, since they are identical except for the std::move calls. Here is what I have, and I want to know if I did it correctly. I'm unsure about using T& and T in my check_move overloads, and whether passing T by value worsens the time complexity or not.
#include <string>
#include <iostream>
struct foo {
std::string a, b;
foo (const std::string& a, const std::string& b) : a(a), b(b) { }
};
template <typename T> void bar (const T&) { }
template <typename T> void bar (T&&) { }
template <typename T>
T check_move (const foo&, T& t) { std::cout << "std::move not called.\n"; return t; }
template <typename T>
T&& check_move (foo&&, T t) { std::cout << "std::move called.\n"; return std::move(t); }
template <typename F>
void execute_helper (F&& f) {
// etc...
bar(check_move(std::forward<F>(f), f.a));
// etc...
bar(check_move(std::forward<F>(f), f.b));
// etc...
bar(check_move(std::forward<F>(f), std::forward<F>(f)));
// etc...
}
void execute (const foo& f) {
execute_helper(f);
}
void execute (foo&& f) {
execute_helper(std::forward<foo>(f));
}
// Test
foo make_foo() {
return foo("hello", "bye");
}
int main() {
foo f("hello", "bye");
execute(f);
execute(make_foo());
}
Output:
std::move not called.
std::move not called.
std::move not called.
std::move called.
std::move called.
std::move called.
Related
Long story for this question at the end.
What is the easiest way to create a function behaving like std::forward but returning an lref for everything that is an lref and a const & ref in all other cases? E.g. with the following "conversion" table:
arg
myforward(arg)
T&
T&
T&&
const T&
const T&
const T&
const T&&
const T&
My main question is why the obvious method is not working for me (having four function accepting T&, T&&, const T&, const T&& with only the first returning a T&. Code I'm currently using (note, helper for monitoring creation and deletion of objects and printing types at the end):
#include <iostream>
using namespace std;
// Implementation #1
template <typename T> T & flr1(T & value) {/* std::cout<<" picked flr1 &"<<endl;*/ return value;};
template <typename T> const T &flr1(T && value) {/* std::cout<<" picked flr1 &&"<<endl; */return static_cast<const T&>(value);};
template <typename T> const T & flr1(const T & value) {/* std::cout<<" picked flr1 const &"<<endl; */return static_cast<const T&>(value);};
template <typename T> const T & flr1(const T && value) {/* std::cout<<" picked flr1 const &&"<<endl; */return static_cast<const T&>(value);};
// Implementation #2 (same results as #1)
//template<typename T> using myremove_cref_t = typename remove_const<typename remove_reference<T>::type>::type;
//template <typename T> myremove_cref_t<T> & flr2(myremove_cref_t<T> & value) { return value;};
//template <typename T> const myremove_cref_t<T> &flr2(myremove_cref_t<T> && value) { return value;};
//template <typename T> const myremove_cref_t<T> & flr2(const myremove_cref_t<T> & value) { return value;};
//template <typename T> const myremove_cref_t<T> & flr2(const myremove_cref_t<T> && value) { return value;};
// Implementation #3
template <typename T> struct forwardLRefOrConst { typedef T &type; static const char *name() {return "generic";}};
template <typename T> struct forwardLRefOrConst<T&> { typedef T &type; static const char *name() {return "T&";}};
template <typename T> struct forwardLRefOrConst<T &&> { typedef const T &type; static const char *name() {return "T &&";}};
template <typename T> struct forwardLRefOrConst<const T &> { typedef const T &type; static const char *name() {return "const T&";}};
template <typename T> using forwardLRefOrConst_t = typename forwardLRefOrConst<T>::type;
template <typename T> forwardLRefOrConst_t<T> flr3(T &value) { return static_cast<forwardLRefOrConst_t<T>>(value); }
// Test code
template <typename T> void test2(const char *name, T && arg)
{
cout<<" test "<<name<<" is "<<Name<decltype(arg)>::name()<<endl;
}
template <typename T> void test(T &&arg)
{
cout<<" test arg is "<<Name<decltype(arg)>::name()<<endl;
test2("flr1(arg)",flr1<T>(arg)); // Implementation 1
test2("flr1(std::forward(arg))",flr1<T>(std::forward<T>(arg))); // Implementation 1 bis
test2("flr3(arg)",flr3<decltype(arg)>(arg)); // Implementation 3
}
int main()
{
cout<<"Initialization"<<endl;
ClassA a1;
const ClassA a2;
ClassA &a3(a1);
ClassA &&a4=ClassA();
const ClassA &&a5=ClassA();
cout<<("Test (T)")<<endl;
test(a1);
cout<<("Test (const T)")<<endl;
test(a2);
cout<<("Test (T &)")<<endl;
test(a3);
cout<<("Test (T &&)")<<endl;
test(std::forward<ClassA>(a4));
cout<<("Test (immediate)")<<endl;
test(ClassA());
cout<<("Test (const T&&)")<<endl;
test(a5);
cout<<"End"<<endl;
return 0;
}
This program generates the following output
Initialization
Constructed A1
Constructed A2
Constructed A3
Constructed A4
Test (T)
test arg is &T
test flr1(arg) is &T
test flr1(std::forward(arg)) is &T
test flr3(arg) is &T
Test (const T)
test arg is const &T
test flr1(arg) is const &T
test flr1(std::forward(arg)) is const &T
test flr3(arg) is const &T
Test (T &)
test arg is &T
test flr1(arg) is &T
test flr1(std::forward(arg)) is &T
test flr3(arg) is &T
Test (T &&)
test arg is &&T
test flr1(arg) is &T
test flr1(std::forward(arg)) is const &T
test flr3(arg) is const &T
Test (immediate)
Constructed A5
test arg is &&T
test flr1(arg) is &T
test flr1(std::forward(arg)) is const &T
test flr3(arg) is const &T
Destroyed A5
Test (const T&&)
test arg is const &T
test flr1(arg) is const &T
test flr1(std::forward(arg)) is const &T
test flr3(arg) is const &T
End
Destroyed A4
Destroyed A3
Destroyed A2
Destroyed A1
As visible above only flr1<T>(std::forward<T>(arg)) or flr3<decltype(arg)>(arg) give the expected result but they are both too verbose for my taste. I would like to have a simple function myforward(arg) or at worst myfoward<T>(arg). Is there any way to achieve that?
/* Test class for arguments */
static int index=1;
template <int I> struct TestClass
{
TestClass(int val): val(val)
{
cout<<" Constructed "<<id()<<val<<endl;
if(index<=val)
index=val+1;
}
TestClass(): val(index++)
{
cout<<" Constructed "<<id()<<val<<endl;
}
TestClass(const TestClass<I> &value): val(index++)
{
cout<<" Constructed from "<<id()<<value.val<<" to "<<id()<<val<<endl;
}
TestClass(TestClass<I> &&value): val(index++)
{
cout<<" Moved "<<id()<<value.val<<" to "<<id()<<val<<endl;
val=value.val;
value.val=0;
}
void operator =(TestClass &&value)
{
cout<<" Assign moved "<<id()<<value.val<<" to "<<id()<<val<<endl;
val=value.val;
value.val=0;
}
void operator =(const TestClass &value)
{
cout<<" Assign copied "<<id()<<value.val<<" to "<<id()<<val<<endl;
}
~TestClass()
{
if(val)
cout<<" Destroyed "<<id()<<val<<endl;
}
char id() const {return 'A'+I;}
int val;
};
typedef TestClass<0> ClassA;
typedef TestClass<1> ClassB;
/* Functions to print a data type */
template <typename T> struct Name
{
static std::string name()
{
std::string ret;
if(std::is_const<T>())
ret="const ";
if(std::is_lvalue_reference<T>())
ret+=Name<typename std::remove_reference<T>::type>::name();
else if(std::is_rvalue_reference<T>())
ret+=Name<typename std::remove_reference<T>::type>::name();
else
ret+="T";
return ret;
}
};
template <typename T> struct Name<T &>
{
static std::string name()
{
std::string ret;
if(std::is_const<T>())
ret="const ";
ret+="&T";
return ret;
}
};
template <typename T> struct Name<T &&>
{
static std::string name()
{
std::string ret;
if(std::is_const<T>())
ret="const ";
ret+="&&T";
return ret;
}
};
I'm currently creating a small C++/Qt wrapper for Sqlite. I've written in the Query all the overloads for binding:
bool bind(int col, int value);
bool bind(int col, double value);
and the ones for fetching:
bool columnSingle(int col, int &value);
bool columnSingle(int col, double &value);
Together with its parameter pack variants:
template <typename ...T> bool bindMany(int startCol, const T &...values);
template <typename ...T> bool fetchMany(int startCol, T &...values);
and its version working with tuples.
Now I'm currently working on a function that performs in a single operation the bind of N parameters, a single step and the fetch of M columns:
template <int N, typename ...T> bool querySingle(T &&...values);
In its body I transform values to a tuple (Let's call it A) and then create from it two tuples:
The first containing the first N values and the other the remaining ones.
The problem is that if I create it with std::forward_as_tuple the fetching part will work even if I pass a immediate instead of throwing an error as expected.
e.g.
querySingle<2>(4, "Foo", 5 /* This should give an error, all parameters after the 2nd should be an lref */ , a);
I was thus trying to create a forward function behaving as described above.
I would simply do
template <typename T>
decltype(auto) myforward(T&& value)
{
if constexpr (std::is_rvalue_reference_v<T&&>
or std::is_const_v<std::remove_reference_t<T>>) {
return static_cast<const T&>(value);
} else {
return static_cast<T&>(value);
}
}
Demo
As visible above only flr1<T>(std::forward<T>(arg)) or flr3<decltype(arg)>(arg) give the expected result
Notice that inside the function:
template <typename T> void test(T&& arg)
arg has name and is so a l-value. To keep/retrieve its original form, you have either to std::forward<T>(arg) or provide T to your template and work accordingly:
template <typename T, typename U>
decltype(auto) myforward2(U&& value)
{
if constexpr (std::is_rvalue_reference_v<T&&>
or std::is_const_v<std::remove_reference_t<T>>) {
return static_cast<const T&>(value);
} else {
return static_cast<T&>(value);
}
}
template <typename T>
decltype(auto) test(T&& arg)
{
return myforward2<T>(arg); // arg is l-value here
}
Demo
Issue is that different compiler's produces different output (clang/gcc) and so that makes me think that this usage is undefined behavour. However my goal is to deduce const when assigning reference.
Output with:
clang-3.6 -> not const
gcc-4.8.4 -> const
#include <iostream>
#include <type_traits>
struct AnyReference {
template <typename RT> AnyReference(RT &a_var) : _ptr(&a_var) {}
template <typename T> operator T &() const
{
if (std::is_const<T>::value) {
std::cout << "const\n";
}
else {
std::cout << "not const\n";
}
return *reinterpret_cast<T *>(_ptr);
}
void *_ptr;
};
int main()
{
int i(5);
AnyReference a(i);
const int &c = a;
}
One possibility based on idea of Ben Voight
struct AnyReference {
template <typename RT> AnyReference(RT &a_var) : _ptr(&a_var) {}
template <typename T> operator T &() const { return operatorTand<T>(); }
template <typename T> operator const T &() const
{
return operatorTand<const T>();
}
private:
template <typename T> T &operatorTand() const
{
if (std::is_const<T>::value) {
std::cout << "const\n";
}
else {
std::cout << "not const\n";
}
return *reinterpret_cast<T *>(_ptr);
}
void *_ptr;
};
I'd like to call template<typename T> foo(T x) and manually handle these cases: T = std::vector<U>, T = std::string, T = any other case.
Here's what I wrote for that:
#include <iostream>
#include <vector>
#include <string>
template<typename T> void foo_impl(const std::string &data, std::string *) {
std::cout << "foo for std::string called\n";
}
template<typename T> void foo_impl(const T &data, T *) {
std::cout << "foo for general types called\n";
}
template<typename T> void foo_impl(const std::vector<T> &data, std::vector<T> *) {
std::cout << "foo for std::vector<T> called\n";
}
template<typename T> void foo(const T &data) {
foo_impl(data, static_cast<T*>(nullptr));
}
int main() {
int i = 1;
foo(i);
std::vector<int> a = {0, 1};
foo(a);
std::string s = "abcd";
foo<std::string>(s);
return 0;
}
However, foo(std::string x) is called as in case "T is any other type". How do I deal with it?
For template:
template<typename T> void foo(const T &data) {
std::cout << "foo for general types called\n";
}
Following is a specialization:
template<> void foo<>(const std::string &data) {
std::cout << "foo for std::string called\n";
}
but simple overload seems more appropriate:
void foo(const std::string &data) {
std::cout << "foo for std::string called\n";
}
As partial specialization is not possible for function, you have to make a overload for vector case:
template<typename T, typename Alloc> void foo(const std::vector<T, Alloc> &data) {
std::cout << "foo for std::vector<T, Alloc> called\n";
}
An alternative is to forward to a class/struct which can be (partially) specialized:
template <typename T>
struct foo_impl {
void operator (const T&) const
{
std::cout << "foo for general types called\n";
}
};
// specialization for std::string
template <>
struct foo_impl<std::string>
{
void operator (const T&) const
{
std::cout << "foo for std::string called\n";
}
};
// partial specialization for std::vector
template <typename T, typename A>
struct foo_impl<std::vector<T, A>>
{
void operator (const std::vector<T, A>&) const
{
std::cout << "foo for std::vector<T, A> called\n";
}
};
template <typename T>
void foo(const T& t)
{
foo_impl<T>{}(t);
}
T from template<typename T> void foo_impl(const std::string &data, std::string *) is non-deducible (that is, it's not used in the parameter list of the function), as such, it's not considered as a viable overload.
You can remove the template<typename T> part and make this overload a non-template:
void foo_impl(const std::string &data, std::string *) {
std::cout << "foo for std::string called\n";
}
It's not clear to me why you are using two layers of functions..
You can overload foo for std::string and std::vector<T>.
#include <iostream>
#include <vector>
#include <string>
template<typename T> void foo(const T &data) {
std::cout << "foo for general types called\n";
}
template <typename T> void foo(const std::vector<T> &data) {
std::cout << "foo for std::vector<T> called\n";
}
void foo(const std::string &data) {
std::cout << "foo for std::string called\n";
}
int main() {
int i = 1;
foo(i);
std::vector<int> a = {0, 1};
foo(a);
std::string s = "abcd";
foo(s);
return 0;
}
Output:
foo for general types called
foo for std::vector<T> called
foo for std::string called
I want to explicitly instantiate template member but without instantiation of the template class. But I am getting compiler errors, so is this possible ? Here is my code:
//mytemplate.h
template <class T>
class mytemplate
{
public:
mytemplate(T* tt)
{
mT = tt;
}
template<class B>
void print(const B& bb);
T* mT;
};
//in mytemplate.cpp
#include "mytemplate.h"
template<typename T>
template<typename B>
void mytemplate<T>:: print(const B& bb)
{
B b = bb;
}
template<typename T> void mytemplate<T>::print<float>(const float&) const;
template<typename T> void mytemplate<T>::print<int>(const int&) const;
// main.cpp
int main()
{
int d =0;
mytemplate<int> k(&d);
k.print<float>(4.0);
}
With templates, it always helps to decompose the problem into the smallest possible building block. mytemplate::print can be written in terms of a call to a template free function.
This way you can achieve the effect of partial specialisation of a member function.
A leading question here is "what should the print() method do?". Here is an example in which mytemplate<T> provides a printing policy to a free function. There is no reason of course that the policy could not be some other class which has been constructed via some other (possibly specialised) template free function.
// Policy is a concept which supports 2 methods:
// print_prefix() and print_postfix()
//
template<class Policy, class B>
void print_with_policy(const Policy& policy, const B& value) const
{
policy.print_prefix();
cout << value;
policy.print_postifx();
}
template<class T>
struct mytemplate
{
// implement in terms of a free function
template<class B> void print(const B& value) {
print_with_policy(*this, value);
}
// policy concept implementation
void print_prefix() const {
cout << "prefix-";
}
void print_postfix() const {
cout << "-postfix";
}
};
extending the example to use a separate policy class with a specialisation for strings:
template<typename B>
struct default_policy {
default_policy(const B& value) : _value(value) {}
void operator()() const {
cout << "(" << _value << ")";
}
private:
const B& _value;
};
template<typename B>
struct quoted_policy {
quoted_policy(const B& value) : _value(value) {}
void operator()() const {
cout << '"' << _value << '"';
}
private:
const B& _value;
};
template<class B>
default_policy<B> make_policy(const B& value) {
return default_policy<B>(value);
}
// overload for B being a string
quoted_policy<std::string> make_policy(const std::string& value) {
return quoted_policy<std::string>(value);
}
template<class T>
struct mytemplate
{
// implement in terms of a free function
template<class B> void print(const B& value) {
make_policy(value)();
cout << endl;
}
};
int main()
{
struct foo{};
mytemplate<foo> fooplate;
fooplate.print(int(8));
fooplate.print(std::string { "a string" });
fooplate.print("not a string");
return 0;
}
output:
(8)
"a string"
(not a string)
I would like to have a class member function which returns a pointer to a resource. The resource should be locked and unlocked automatically. I think of creating a non-copyable object which handles the locking.
Do you think the following is a good solution? Is it thread-safe? Are there already tools in the STL for this use case?
template<typename T, typename M>
struct LockedResource
{
private:
T* data_;
std::unique_lock<std::mutex> lock_;
public:
LockedRessource(T* data, M& mtx) : data_{data}, lock_{mtx} {}
T* data() const { return data_; }
};
Use case example:
#include <iostream>
#include <mutex>
#include <thread>
#include <vector>
class Foo {
private:
std::vector<int> data_;
std::mutex mtx_;
public:
LockedResource<std::vector<int>,std::mutex> data()
{ return LockedResource<std::vector<int>,std::mutex>{&data_, mtx_}; }
};
Foo foo;
void worker(int worker, int iterations, int dt) {
for(int i=0; i<iterations; i++) {
std::this_thread::sleep_for(std::chrono::milliseconds(dt));
auto res = foo.data();
// we now have a unique_lock until the end of the scope
std::cout << "Worker " << worker << " adding " << i << std::endl;
res.data()->push_back(i);
}
}
int main() {
std::thread t1{worker, 1, 10, 173};
std::thread t2{worker, 2, 20, 87};
t1.join();
t2.join();
}
This idea - of providing a handle that encapsulates both access to a synchronized object and the necessary locking - is not new: see Enforcing Correct Mutex Usage with Synchronized Values.
I liked Rook's idea to use a unique_ptr with a custom deleter for the handle, so I came up with one:
template <typename BasicLockable>
class unlock_deleter {
std::unique_lock<BasicLockable> lock_;
public:
unlock_deleter(BasicLockable& mtx) : lock_{mtx} {}
unlock_deleter(BasicLockable& mtx, std::adopt_lock_t a) noexcept : lock_{mtx, a} {}
template <typename T>
void operator () (T*) const noexcept {
// no-op
}
};
template <typename T, typename M = std::mutex>
using locked_ptr = std::unique_ptr<T, unlock_deleter<M>>;
which is used in the implementation of a template class synchronized that wraps an object and a mutex:
template <typename T, typename M = std::mutex>
class synchronized {
T item_;
mutable M mtx_;
// Implement Copy/Move construction
template <typename Other, typename N>
synchronized(Other&& other, const std::lock_guard<N>&) :
item_{std::forward<Other>(other).item_} {}
// Implement Copy/Move assignment
template <typename Other>
void assign(Other&& other) {
std::lock(mtx_, other.mtx_);
std::lock_guard<M> _{mtx_, std::adopt_lock};
std::lock_guard<decltype(other.mtx_)> _o{other.mtx_, std::adopt_lock};
item_ = std::forward<Other>(other).item_;
}
public:
synchronized() = default;
synchronized(const synchronized& other) :
synchronized(other, std::lock_guard<M>(other.mtx_)) {}
template <typename N>
synchronized(const synchronized<T, N>& other) :
synchronized(other, std::lock_guard<N>(other.mtx_)) {}
synchronized(synchronized&& other) :
synchronized(std::move(other), std::lock_guard<M>(other.mtx_)) {}
template <typename N>
synchronized(synchronized<T, N>&& other) :
synchronized(std::move(other), std::lock_guard<N>(other.mtx_)) {}
synchronized& operator = (const synchronized& other) & {
if (&other != this) {
assign(other);
}
return *this;
}
template <typename N>
synchronized& operator = (const synchronized<T, N>& other) & {
assign(other);
return *this;
}
synchronized& operator = (synchronized&& other) & {
if (&other != this) {
assign(std::move(other));
}
return *this;
}
template <typename N>
synchronized& operator = (synchronized<T, N>&& other) & {
assign(std::move(other));
return *this;
}
template <typename N>
void swap(synchronized<T, N>& other) {
if (static_cast<void*>(&other) != static_cast<void*>(this)) {
std::lock(mtx_, other.mtx_);
std::lock_guard<M> _{mtx_, std::adopt_lock};
std::lock_guard<N> _o{other.mtx_, std::adopt_lock};
using std::swap;
swap(item_, other.item_);
}
}
locked_ptr<T, M> data() & {
return locked_ptr<T, M>{&item_, mtx_};
}
locked_ptr<const T, M> data() const& {
return locked_ptr<const T, M>{&item_, mtx_};
}
};
template <typename T, typename M, typename N>
void swap(synchronized<T, M>& a, synchronized<T, N>& b) {
a.swap(b);
}
Taking care to synchronize copies/moves/swaps properly as well. Here's your sample program live at Coliru.