Compiler infering the template argument - c++

template<typename T>
class A
{
public:
A(T &t)
: t_(t){}
T t_;
};
int main()
{
int value;
A<decltype(value)> a(value);
// what I wish for : A a(value);
// which does not compile "missing template argument before 'a'"
}
Is there a way in the declaration of A (or somewhere else) to hint the compiler that T should be automatically resolved to the type passed to the constructor ?
(ideally c++11, but happy to hear about less old versions)

C++17 does it out of the box (or with the help of deduction guides), previous versions cannot.

As answered by #Quentin, this is only possible starting in C++17. However, if you're fine with calling a function to create your A objects, the following should do what you want in C++11:
template <class T, class NonRefT = typename std::remove_reference<T>::type>
A<NonRefT> create_A (T && t) {
return A<NonRefT>(std::forward<T>(t));
}
// Or even closer to your original code:
template <class T>
auto create_A (T && t) -> A<decltype(t)> {
return A<decltype(t)>(std::forward<T>(t));
}
I used std::remove_reference based on your use of decltype, though you might want to use std::decay instead.
int main () {
int value = 5;
auto a = create_A(value);
}
If I remember correctly the example code has an edge-case where it does not work as expected pre-C++17. The compiler will elide the copy/move constructor to create a from the rvalue returned by create_A(). However, it will check during compilation whether A's copy/move constructor (which it won't use) is available/accessible. Starting from C++17 the copy/move elision is done "properly" and no copy/move constructor is necessary for such code. (Also, I might be misremembering and it might be checking for copy/move assignment instead.)

In C++11 you can create a simple make_A function like this:
#include <iostream>
template <typename T>
class A {
public:
A(T &t) : t_(t) {}
T t_;
};
template <typename T>
A<T> make_A(T&& t) {
return A<T>(std::forward<T>(t));
}
int main() {
int value = 0;
auto a = make_A(value);
return 0;
}
Demo

Related

Pass object with derived template to function that accepts object with base template

How do I pass an object with a derived template instantiation to a method accepting those objects with a base template instantiation?
It seems possible, as std::shared_ptr or std::pair seem capable to do it.
E.g.
#pragma once
#include <iostream>
#include <memory>
struct Base {
virtual void print() = 0;
};
struct Derived : public Base {
void print() {
std::cout << "Got it!" << std::endl;
}
};
void printBase(const std::shared_ptr<Base> &ptr){
ptr->print();
}
void printBase(const std::pair<Base&, Base&> &pr){
pr.first.print();
}
template <typename T>
struct Wrap {
T& t;
};
void printBase(const Wrap<Base> &wrap) {
wrap.t.print();
}
int main() {
Derived d;
std::shared_ptr<Derived> ptr = std::make_shared<Derived>(d);
printBase(ptr); // works
std::pair<Derived&, Derived&> pr = {d, d};
printBase(pr); // works
Wrap<Derived> w = Wrap<Derived>{d};
// printBase(w); // gives compile error
}
You will need to explicitly add a conversion constructor and/or assignment operator to your Wrapped type to be able to convert from different types.
This is how both std::shared_ptr and std::pair do this internally; shared_ptr<T> can be constructed from shared_ptr<U> types (with SFINAE restrictions that U* is convertible to T*), and pair<T,U> can be constructed from pair<T2,U2> types (with SFINAE restrictions that T2 is convertible to T and U2 is convertible to U).
Doing this can be as simple as adding a new constructor:
template <typename T>
struct Wrap
{
Wrap(T& ref)
: t{ref}
{
}
template <typename U, typename = std::enable_if_t<std::is_convertible_v<U&, T&>>>
Wrap(const Wrap<U>& other)
: t{other.t}
{
}
T& t;
};
The above example uses is_convertible as a condition for enable_if so the constructor is only visible when references of U can be converted to references of T. This will constrain it such that U must be hierarchically related to T (since references aren't convertible otherwise) -- which would allow a Wrapped<Derived> to be converted to Wrapped<Base>, but not vice-versa.
Edit: As mentioned in the comments, it's worth noting that, unlike types that are part of a hierarchy -- where a reference to Derived can be passed as a reference to Base, types that wrap hierarchies will not be able to pass a reference to a Template<Derived> as a reference to a Template<Base>.
The examples with a std::shared_ptr<Derived> being passed to a const std::shared_ptr<Base>& only actually work due to const-lifetime extension in C++. This doesn't actually pass it as a reference -- but instead materializes a temporary object of std::shared_ptr<Base> which gets passed to the reference. It's effectively the same as passing-by-value.
This also means that you cannot have a Template<Derived> be passed to a non-const Template<Base> reference, since lifetime extension only occurs for const references.
Edit: As discussed in the comments:
Making the constructor a copy conversion is not required; it could easily be an R-value constructor instead. However, if you are doing cleanup on destruction of the wrapped type, then you will need to somehow flag that the moved-from object does not need to be cleaned up. The easiest way is using pointers, where you rebind to nullptr after moving:
template <typename T>
struct Wrap
{
Wrap(T& ref)
: t{std::addressof(ref)}
{
}
Wrap(Wrap&& other)
: t{other.t}
{
other.t = nullptr;
}
Wrap(const Wrap&) = delete;
template <typename U, typename = std::enable_if_t<std::is_convertible_v<U&, T&>>>
Wrap(Wrap<U>&& other)
: t{other.t}
{
other.t = nullptr;
}
~Wrap() {
if (t != nullptr) {
cleanup(*t); // some cleanup code
}
}
T* t;
};
If pointers aren't possible for your desired API, then you may need to use a bool needs_cleanup that gets set appropriately during moves, since references cannot be rebound.
Note: if the data is private and not public as in this example, you may need to have a friend declaration of:
template <typename> friend class Wrap;
So that a Wrap<T> may access the private data members of a Wrap<U>.
Change printBase function to the following one:
template <typename T, typename = std::enable_if<std::is_base_of_v<Base, T>>>
void printBase(const Wrap<T> &wrap){
wrap.t.print();
}

Template parameter can't be deduced on implicitly constructed argument

I would like to have the following code in c++17:
#include <iostream>
#include <string>
#include <type_traits>
#include <functional>
class Foo;
template<class T>
class Bar {
public:
std::function<T(Foo&)> m_fn;
template<class Fn>
Bar(Fn fn) : m_fn(fn) {};
T thing(Foo &foo) const {
return m_fn(foo);
}
};
template<class Fn>
Bar(Fn) -> Bar<decltype(std::invoke(std::declval<Fn>(),
std::declval<Foo&>()))>;
class Foo {
public:
Foo() {};
template<class T>
std::vector<T> do_thing(const Bar<T> &b) {
std::vector<T> r;
r.push_back(b.thing(*this));
return r;
}
};
std::string test(Foo &) {
return "hello";
}
int main() {
Foo foo = Foo();
// works
std::vector<std::string> s = foo.do_thing(Bar{test});
// cant deduce T parameter to do_thing
std::vector<std::string> s = foo.do_thing({test});
}
But compiling this gives me "couldn't deduce template parameter ‘T’" on the call to do_thing.
Having do_thing(Bar{test}) fixes this and works fine but equates to some ugly code in the real code equivalent. I would like to have do_thing({test}) or do_thing(test) implicitly construct a Bar and pass that as the argument if possible.
I also don't want to forward declare a variable to pass into do_thing either
Is there some way to guide the inference of template argument T so that the call to do_thing can stay clean?
Edit:
Sorry for the late edit, but the arguments to the Bar constructor are over simplified in the example I included. In reality, there is an extra parameter std::optional<std::string> desc = std::nullopt and that might change in the future (although unlikely). So constructing the Bar inside do_thing would be a bit hard to maintain...
would like to have do_thing({test}) or do_thing(test) implicitly construct a Bar and pass that as the argument if possible.
Unfortunately, when you call do_thing({test}) or do_thing(test), test (or {test}) isn't a Bar<T> object. So the compiler can't deduce the T type and can't construct a Bar<T> object.
A sort of chicken-and-egg problem.
The best I can imagine is to add, in Foo, a do_test() method as follows
template<typename T>
auto do_thing (T const & t)
{ return do_thing(Bar{t}); }
This way you can call (without graphs)
std::vector<std::string> s = foo.do_thing(test);
You get the same result as
std::vector<std::string> s = foo.do_thing(Bar{test});
-- EDIT --
The OP ask
is there any way of preserving the {test} brace syntax? maybe with initializer_list or something?
Yes... with std::initializer_list
template<typename T>
auto do_thing (std::initializer_list<T> const & l)
{ return do_thing(Bar{*(l.begin())}); }
but, this way, you accept also
std::vector<std::string> s = foo.do_thing(Bar{test1, test2, test3});
using only test1
Maybe a little better... another way can be through a C-style array
template <typename T>
auto do_thing (T const (&arr)[1])
{ return do_thing(arr[0]); }
This way you accept only an element.
This happens because {} is not an expression and can only be used in limited ways while doing argument deduction, the parameter must have specific forms in order to succeed.
The allowed parameters types that can be used to deduce template parameters when {} is involved are better expanded in [temp.deduct.call]/1, two of the examples extracted from the cited part of the standard are:
template<class T> void f(std::initializer_list<T>);
f({1,2,3}); // T deduced to int
template<class T, int N> void h(T const(&)[N]);
h({1,2,3}); // T deduced to int
In your example the deduction guide is not used to deduce the T for {test} for the same as above.
foo.do_thing(Bar{test});
is your direct option without using additional functions.

When does && mean 'forwarding reference'?

When compiled, the following code causes this error:
'Container::Wrapper::Wrapper(S)': member function already
defined or declared
Does the compiler think S&& in the constructor of Wrapper is a forwarding reference?
template<typename T>
struct Container
{
template<class S>
struct Wrapper {
S obj;
Wrapper(S&& obj) : obj(std::forward<S>(obj)){}
Wrapper(const S& obj) : obj(obj){}
};
template<class S>
void push_back(S&& obj) {
void *storage = malloc(sizeof(Wrapper<S>));
new (storage) Wrapper<S>(std::forward<S>(obj));
}
};
struct Foobar{};
int main()
{
Container<Foobar> cont;
Foobar foobar;
cont.push_back(foobar);
return 0;
}
Looking at an example from here, I don't understand how what I'm doing is any different:
template <class T, class Allocator = allocator<T> >
class vector {
public:
...
void push_back(T&& x); // fully specified parameter type ⇒ no type deduction;
... // && â‰Ħ rvalue reference
};
Edit:
The solution to this issue was to modify push_back to remove the reference from the type being used to instantiate the Wrapper:
template<class S>
void push_back(S&& obj) {
typedef std::remove_reference<S>::type U;
void *storage = malloc(sizeof(Wrapper<U>));
new (storage) Wrapper<U>(std::forward<S>(obj));
}
There are no universal references involved it the implementation of Wrapper. The only universal reference in your code is Container<>::push_back's parameter.
When you call cont.push_back(foobar);, parameter S of push_back is deduced as Foobar &.
Later you attempt to instantiate your Wrapper<S> with S == Foobar &. Reference collapsing rules dictate that in Wrapper's constructor parameter declarations S && turns into Foobar & and const S & also turns into Foobar &.
This means that you end up with two supposedly "overloaded" Wrapper::Wrapper constructors, which have identical signatures. This is the reason for the error message you observe.
If you attempt to instantiate std::vector with a template argument of lvalue reference type, you will run into exactly the same problem for its push_back overloads. However, with such an attempt compilation will typically fail miserably for other reasons, well before it gets to push_back overloads.
A more distilled example would look as follows
template <typename T> struct MyVector {
void foo(T &&) {}
void foo(const T &) {}
};
int main() {
MyVector<int &> v;
}
and will produce the same error.
The fairly non-obvious part here is that const T & with T = U & actually becomes U & and not const U &. But that's indeed the case.

How do I bind a member function template passing unspecified call wrapper

I tried to compile the following example using VC11 and g++ 4.7.2:
#include <functional>
class X {
public:
template <typename T>
explicit X(T t)
{
std::bind(&X::invoke<T>, this, t)();
}
private:
template <typename T>
void invoke(T t)
{
t();
}
};
class Y {
public:
void foo() {
//...
}
};
int main() {
Y y;
X x(std::bind(&Y::foo, &y));
return 0;
}
but it finished with errors. I'm not sure if it is reasonable to paste the whole compilers output but generally
vc11 says:
error C2664: 'void std::_Pmf_wrap::operator ()(_Farg0 &,_V0_t) const' : cannot convert parameter 3 from 'void' to 'std::_Bind,Y *,std::_Nil,std::_Nil,std::_Nil,std::_Nil,std::_Nil,std::_Nil>' c:\program files (x86)\microsoft visual studio 11.0\vc\include\functional 1152 1 ConsoleApplication1 (Microsoft Visual C++ Compiler Nov 2012 CTP)
and g++:
Compilation finished with errors:
source.cpp: In instantiation of 'X::X(T) [with T = std::_Bind(Y*)>]':
source.cpp:28:33: required from here
source.cpp:8:9: error: no match for call to '(std::_Bind_helper(Y*)>), X* const, std::_Bind(Y*)>&>::type {aka std::_Bind(Y*)>)>(X*, std::_Bind(Y*)>)>}) ()'
Is there a way to solve this issue. It's very important for me, to save the main idea - a class that can be instantiated with any callable object (function object, function pointer or call wrapper returned by std::bind() function).
I would be grateful if someone help.
P.S. It compiles if I create an instance of X, passing function object or function pointer.
I think they omitted an important bit of boost::bind when adopting it into std::bind, namely boost::protect(). Your code can be fixed like the following:
#include <boost/bind/protect.hpp>
// ...
X x(boost::protect(std::bind(&Y::foo, &y)));
Or, alternatively:
template <typename T>
explicit X(T t)
{
auto tt = boost::protect(t);
auto f = std::bind(&X::invoke<decltype(tt)>, this, tt);
f();
}
See http://www.boost.org/doc/libs/1_53_0/libs/bind/bind.html
Although the first argument is, by default, not evaluated, all other arguments are. Sometimes it is necessary not to evaluate arguments subsequent to the first, even when they are nested bind subexpressions. This can be achieved with the help of another function object, protect, that masks the type so that bind does not recognize and evaluate it. When called, protect simply forwards the argument list to the other function object unmodified.
The header boost/bind/protect.hpp contains an implementation of protect. To protect a bind function object from evaluation, use protect(bind(f, ...)).
The upcoming Effective C++11: Content and Status by Scott Meyers is going to recommend prefer lambdas to std::bind. In C++11 you can simply do:
template <typename T>
explicit X(T t)
{
auto f = [t, this]() { this->invoke(t); };
f();
}
// ...
X x([&y](){ y.foo(); });
The root cause of the problem seems to be the internal copying of its arguments performed by std::bind, with particular reference to t.
You may want to workaround it this way:
template <typename T>
explicit X(T t)
{
std::bind(&X::invoke<T>, this, std::placeholders::_1)(t);
// ^^^^^^^^^^^^^^^^^^^^^ ^
}
This will also work, but you won't be allowed to make the result of bind outlive the argument t (otherwise, you would be passing a dangling reference to invoke<T>()):
template <typename T>
explicit X(T t)
{
std::bind(&X::invoke<T>, this, cref(t))();
// ^^^^^^^
}
UPDATE:
The above solutions are workarounds that help for achieving what you are showing in your example. However, it emerged from the comments that your use case may be quite different (e.g. passing around the result of bind for later evaluation).
As correctly pointed out by Maxim Yegorushkin in his answer, the conceptually correct solution consists in using a construct such as Boost's protect.
In case you do not want to use Boost, it is quite easy to define your own protect() function using C++11's variadic templates:
// Imitates boost::protect, but with variadic templates and perfect forwarding
namespace detail
{
template<typename F>
struct protect
{
private:
F _f;
public:
explicit protect(F f): _f(f)
{
}
template<typename... Ts>
auto operator () (Ts&&... args) ->
decltype(_f(std::forward<Ts>(args)...))
{
return _f(std::forward<Ts>(args)...);
}
};
}
template<typename F>
detail::protect<F> protect(F&& f)
{
return detail::protect<F>(std::forward<F>(f));
}
Eventually, this is how you could use it in your class, as Maxim suggested:
class X
{
public:
template <typename T>
explicit X(T t)
{
auto pt = protect(t);
std::bind(&X::invoke<decltype(pt)>, this, pt)();
}
private:
template <typename T>
void invoke(T t)
{
t();
}
};

C++ template arguments in constructor

Why doesn't this code compile?
template <class T>
class A
{
public:
A(T t) : t_(t) {}
private:
T t_;
};
int main()
{
A a(5.5);
// A<double> a(5.5); // that's what i don't want to do
}
I want template arguments to be implicit.
Like in this example:
template<class T>
T Foo(T t) { return t; }
// usage:
Foo(5.5);
UPDATE: named-constructor idiom isn't acceptable for me. I want to use this class for RAII.
The only way to do so is const A& a = A::MakeA(t), but it's ugly!
Since you have to name the type of a variable (C++03 can't infer the type of a variable), you can only do:
A<double> a(5.5); // that's what i don't want to do
The situation is a little easier when you needn't make a variable of the type, but want to pass it to some other function. In this case, you define an auxiliary "constructor function" (see std::make_pair):
template <class T>
A<T> make_a(T t) { return A<T>(t); }
and then use it like this:
another_function(make_a(1.1));
In C++0x, you will be able to do even
auto a(make_a(5.5));
to define your variable a.
However, inferring A's argument from its constructor is generally impossible, because you can't tell which specializations have the conversion constructor from a given type. Imagine there's a specialization
template <>
struct A<void>
{
A(double);
};