There are similar questions, but I did not find an answer that works for my problem.
Consider the following code:
#include <cassert>
#include <functional>
#include <iostream>
#include <memory>
#include <utility>
class TestClass
{
public:
TestClass( int value): mValue( value) { }
private:
int mValue;
};
template< typename T> class DeferredCreator
{
public:
template< class... Args> DeferredCreator( Args&&... args):
mpCreator( [=]() -> T*
{ return new T( std::forward< Args>( args)...); }
),
mpObject()
{ }
T* get() {
if (mpObject == nullptr)
mpObject.reset( mpCreator());
return mpObject.get();
}
private:
std::function< T*( void)> mpCreator;
std::unique_ptr< T> mpObject;
};
int main() {
DeferredCreator< int> dcInt( 42);
assert( dcInt.get() != nullptr);
return 0;
}
The idea is that the class DeferredCreator creates an object only when it is really needed. I got this work e.g. for strings, but I can't figure out how to pass a simple integer into my lambda.
The error message I get is:
prog.cpp:19:26: error: no matching function for call to 'forward'
{ return new T( std::forward< Args>( args)...); }
^~~~~~~~~~~~~~~~~~~
prog.cpp:36:27: note: in instantiation of function template specialization 'DeferredCreator<int>::DeferredCreator<int>' requested here
DeferredCreator< int> dcInt( 42);
^
/usr/bin/../lib/gcc/x86_64-linux-gnu/6.3.0/../../../../include/c++/6.3.0/bits/move.h:76:5: note: candidate function not viable: 1st argument ('const int') would lose const qualifier
forward(typename std::remove_reference<_Tp>::type& __t) noexcept
^
/usr/bin/../lib/gcc/x86_64-linux-gnu/6.3.0/../../../../include/c++/6.3.0/bits/move.h:87:5: note: candidate function not viable: 1st argument ('const int') would lose const qualifier
forward(typename std::remove_reference<_Tp>::type&& __t) noexcept
^
2 errors generated.
I already tried to use decltype( args) as template argument for std::forward<>, but that did not help.
The code is also available here: https://ideone.com/MIhMkt
args... is constant because a lambda's call operator is implicitly const. So, if you make your lambda mutable, then it works:
[=]() mutable -> T*
{ return new T( std::forward< Args>( args)...); }
The reason it didn't work with decltype(args) is that the types themselves are not const, just the call operator.
The operator() of the closure type generated by your lambda expression is const-qualified. std::forward can attempt to move args..., which are data members of the closure. const objects cannot be moved.
You can mark your lambda as mutable:
mpCreator( [=]() mutable -> T*
{ return new T( std::forward< Args>( args)...); }
),
This removes the implicit const qualfiier from the closure type's generated operator().
live example on wandbox.org
Related
I want to extend the std namespace by adding template specializations of std::size and std::empty for my custom containers (outside the std).
I have two questions:
Why are std::size and std::empty constexpr? As far as I am aware of only the size and the emptiness of std::array and arrays on the stack can be known at compile time which is not the case for other containers such as std::vector and std::map. So how could std::size and std::empty even work when substituting a std::vector as template parameter for instance?
I tried to extend the std with template specializations of std::size and std::empty for my custom containers, but the compiler could not deduce the specialized template method. Could someone explain what I do wrong?
My code [Try it online in Wandbox]:
#include <iterator>
#include <vector>
namespace dummy {
struct Widget {
bool IsEmpty() const noexcept { return m_v.empty(); }
size_t GetSize() const noexcept { return m_v.size(); }
std::vector< int > m_v;
};
}
namespace std {
template<>
constexpr auto empty(const dummy::Widget &widget)
-> decltype(widget.IsEmpty()) {
return widget.IsEmpty();
}
template<>
constexpr auto size(const dummy::Widget &widget)
-> decltype(widget.GetSize()) {
return widget.GetSize();
}
}
int main() {
std::vector< int > ints;
std::size(ints);
}
Output:
prog.cc:15:17: error: no function template matches function template specialization 'empty'
constexpr auto empty(const dummy::Widget &widget)
^
/opt/wandbox/clang-head/include/c++/v1/iterator:1843:16: note: candidate template ignored: substitution failure [with _Cont = dummy::Widget]: no member named 'empty' in 'dummy::Widget'
constexpr auto empty(const _Cont& __c)
^
/opt/wandbox/clang-head/include/c++/v1/iterator:1850:16: note: candidate template ignored: could not match 'type-parameter-0-0 const[_Np]' against 'const dummy::Widget'
constexpr bool empty(const _Tp (&)[_Sz]) noexcept { return false; }
^
/opt/wandbox/clang-head/include/c++/v1/iterator:1854:16: note: candidate template ignored: could not match 'initializer_list<type-parameter-0-0>' against 'const dummy::Widget &'
constexpr bool empty(initializer_list<_Ep> __il) noexcept { return __il.size() == 0; }
^
prog.cc:22:17: error: no function template matches function template specialization 'size'
constexpr auto size(const dummy::Widget &widget)
^
/opt/wandbox/clang-head/include/c++/v1/iterator:1832:16: note: candidate template ignored: substitution failure [with _Cont = dummy::Widget]: no member named 'size' in 'dummy::Widget'
constexpr auto size(const _Cont& __c)
^
/opt/wandbox/clang-head/include/c++/v1/iterator:1839:18: note: candidate template ignored: could not match 'type-parameter-0-0 const[_Np]' against 'const dummy::Widget'
constexpr size_t size(const _Tp (&)[_Sz]) noexcept { return _Sz; }
I tried to extend the std with template specializations of std::size and std::empty for my custom containers, but the compiler could not deduce the specialized template method. Could someone explain what I do wrong?
std::size signature is:
template <class C>
constexpr auto size( const C& c ) -> decltype(c.size());
your one is different:
template<>
constexpr auto size(const dummy::Widget &widget)
-> decltype(widget.GetSize());
The decltype(..) content is different, you do SFINAE on different method.
So your function isn't not a specialization.
So, unless you add a widget::size() declaration in your class, you cannot specialize that function in std.
Why are std::size and std::empty constexpr?
For function templates, constexpr only means the resulting function will be constexpr if possible. It doesn't mean it will be constexpr for all instantiations. In the case of std::vector, that means that that particular instantiation of std::size will not be.
I tried to extend the std with template specializations of std::size and std::empty for my custom containers, but the compiler could not deduce the specialized template method.
That's because the versions of std::size and std::empty you're attempting to provide specialisations for have a different return type. The standard return type is decltype(c.size()) / decltype(c.empty()). You don't provide size() or empty() member functions, so this cannot possibly work. Just use the standard names.
The proper way to extend std::size is not via specialization.
Instead you should define a free function size in the same namespace as your type (optionally as an inline friend).
Then
using std::size;
std::cout << size( your_container ) << "\n";
works; and your_container replaced with a C array or a std container also works (in generic code).
The requirement to using std::size is annoying. You can work around it:
namespace notstd {
namespace adl_size {
using std::size;
template<class T>
constexpr auto get_size(T const& t)
noexcept( noexcept( size(t) ) )
->decltype( size(t) )
{ return size(t); }
}
template<class T>
constexpr auto size( T const& t )
noexcept( noexcept( ::notstd::adl_size::get_size(t) ) )
-> decltype( ::notstd::adl_size::get_size(t) )
{ return ::notstd::adl_size::get_size(t); }
}
now notstd::size( vector ) and notstd::size( your_container ) and notstd::size( some_array ) all work, and no need to explicitly add using std::size before using it.
I'm trying to make a movable wrapper to non-copyable, non-movable class, however I have a problem passing a const std::string variable to the constructor. The minimal example below produces following error:
#include <iostream>
#include <memory>
#include <string>
#include <utility>
struct X {
std::string x;
X(const std::string &x) : x(x) {}
X(const X &x) = delete;
X(X &&x) = delete;
};
struct Wrapper {
std::unique_ptr<X> x;
Wrapper(const Wrapper & wrapper) = delete;
Wrapper(Wrapper && wrapper) = default;
template<typename... Args>
Wrapper(Args&&... args) : x(std::make_unique<X>(std::forward(args)...)) {}
};
int main() {
const std::string XXX = "XXX";
Wrapper w{XXX};
std::cout << w.x->x << std::endl;
}
Error message here:
forwarding.cc:21:53: error: no matching function for call to 'forward'
Wrapper(Args&&... args) : x(std::make_unique<X>(std::forward(args)...)) {}
^~~~~~~~~~~~
forwarding.cc:26:13: note: in instantiation of function template specialization 'Wrapper::Wrapper<const std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > &>' requested here
Wrapper w{XXX};
^
/usr/bin/../lib/gcc/x86_64-linux-gnu/7.2.0/../../../../include/c++/7.2.0/bits/move.h:73:5: note: candidate template ignored: couldn't infer template argument '_Tp'
forward(typename std::remove_reference<_Tp>::type& __t) noexcept
^
/usr/bin/../lib/gcc/x86_64-linux-gnu/7.2.0/../../../../include/c++/7.2.0/bits/move.h:84:5: note: candidate template ignored: couldn't infer template argument '_Tp'
forward(typename std::remove_reference<_Tp>::type&& __t) noexcept
^
1 error generated.
You need to explicitly pass template parameters to std::forward:
std::forward<Args>(args)...
This is because std::forward needs some way of knowing the "original value category" of args..., which is impossible through template argument deduction alone as args is always an lvalue.
Lvalues will deduced as lvalue references in the context of template argument deduction for forwarding references (as a special rule), so std::forward can do its job by looking at the types inside Args....
Why doesn't the following code compile (in C++11 mode)?
#include <vector>
template<typename From, typename To>
void qux(const std::vector<From>&, To (&)(const From&)) { }
struct T { };
void foo(const std::vector<T>& ts) {
qux(ts, [](const T&) { return 42; });
}
The error message is:
prog.cc:9:5: error: no matching function for call to 'qux'
qux(ts, [](const T&) { return 42; });
^~~
prog.cc:4:6: note: candidate template ignored: could not match 'To (const From &)' against '(lambda at prog.cc:9:13)'
void qux(const std::vector<From>&, To (&)(const From&)) { }
^
But it doesn't explain why it couldn't match the parameter.
If I make qux a non-template function, replacing From with T and To with int, it compiles.
A lambda function isn't a normal function. Each lambda has its own type that is not To (&)(const From&) in any case.
A non capturing lambda can decay to To (*)(const From&) in your case using:
qux(ts, +[](const T&) { return 42; });
As noted in the comments, the best you can do to get it out from a lambda is this:
#include <vector>
template<typename From, typename To>
void qux(const std::vector<From>&, To (&)(const From&)) { }
struct T { };
void foo(const std::vector<T>& ts) {
qux(ts, *+[](const T&) { return 42; });
}
int main() {}
Note: I assumed that deducing return type and types of the arguments is mandatory for the real problem. Otherwise you can easily deduce the whole lambda as a generic callable object and use it directly, no need to decay anything.
If you don't need to use the deduced To type, you can just deduce the type of the whole parameter:
template<typename From, typename F>
void qux(const std::vector<From>&, const F&) { }
Correct me if I am wrong, but template parameters deduction deduces only exact types without considering possible conversions.
As a result the compiler cannot deduce To and From for To (&)(const From&) because qux expects a reference to function, but you provide a lambda which has its own type.
You have left absolutely no chance to compiler to guess what is To. Thus, you need to specify it explicitly.
Also, lambda here needs to be passed by pointer.
Finally, this version compiles ok:
template<typename From, typename To>
void qux(const std::vector<From>&, To (*)(const From&)) { }
struct T { };
void foo(const std::vector<T>& ts) {
qux<T,int>(ts,[](const T&) { return 42; });
}
You're expecting both implicit type conversions (from unnamed function object type to function reference type) and template type deduction to happen. However, you can't have both, as you need to know the target type to find the suitable conversion sequence.
But it doesn't explain why it couldn't match the parameter.
Template deduction tries to match the types exactly. If the types cannot be deduced, deduction fails. Conversions are never considered.
In this expression:
qux(ts, [](const T&) { return 42; });
The type of the lambda expression is some unique, unnamed type. Whatever that type is, it is definitely not To(const From&) - so deduction fails.
If I make qux a non-template function, replacing From with T and To with int, it compiles.
That is not true. However, if the argument was a pointer to function rather than a reference to function, then it would be. This is because a lambda with no capture is implicitly convertible to the equivalent function pointer type. This conversion is allowed outside of the context of deduction.
template <class From, class To>
void func_tmpl(From(*)(To) ) { }
void func_normal(int(*)(int ) ) { }
func_tmpl([](int i){return i; }); // error
func_tmpl(+[](int i){return i; }); // ok, we force the conversion ourselves,
// the type of this expression can be deduced
func_normal([](int i){return i; }); // ok, implicit conversion
This is the same reason why this fails:
template <class T> void foo(std::function<T()> );
foo([]{ return 42; }); // error, this lambda is NOT a function<T()>
But this succeeds:
void bar(std::function<int()> );
bar([]{ return 42; }); // ok, this lambda is convertible to function<int()>
The preferred approach would be to deduce the type of the callable and pick out the result using std::result_of:
template <class From,
class F&&,
class To = std::result_of_t<F&&(From const&)>>
void qux(std::vector<From> const&, F&& );
Now you can pass your lambda, or function, or function object just fine.
I'm working on a function which invokes a supplied function with a variable number of arguments. It compiles and works correctly on Visual Studio 2015, but fails to compile on Clang . I've prepared a demonstration which shows what I'm trying to do. The error I get in Clang is:
prog.cpp: In function 'int main()': prog.cpp:31:2: error: no matching
function for call to 'run(std::vector&, void ()(int&, const
int&), const int&)' ); ^ prog.cpp:7:6: note: candidate:
template void
run(std::vector&, const std::function&,
mutrArgs ...) void run(
^ prog.cpp:7:6: note: template argument deduction/substitution failed: prog.cpp:31:2: note: mismatched types 'const
std::function' and 'void ()(int&, const
int&)' );
#include <functional>
#include <iostream>
#include <vector>
using namespace std;
template<int RepeatTimes, class ... mutrArgs>
void run(
vector<int>& vec,
const function<void(int&, mutrArgs ...)>& mutr,
mutrArgs ... args
)
{
for (int times{0} ; times < RepeatTimes ; ++times)
for (auto& item : vec)
mutr(item, args...);
}
void adder(int& i, const int& val)
{
i += val;
}
int main()
{
vector<int> v{0,1,2,3,4,5,6,7,8,9};
const int addValue{4};
run<2, const int&>(
v,
&adder,
addValue
);
for (auto i : v)
cout << i << " ";
cout << endl;
return 0;
}
run<2, const int&> just state the first argument, but doesn't deactivate deduction.
run<2, const int&>(v, &adder, addValue);
has 2 places to deduce mutrArgs:
addValue -> mutrArgs = { const int& }
&adder which is not a std::function and so fail.
Taking address of function fix that problem
auto call_run = &run<2, const int&>;
call_run(v, &adder, addValue);
Strangely, clang doesn't support the inlined usage contrary to gcc :/
(&run<2, const int&>)(v, &adder, addValue);
If you want to disable deduction, you may make your template arg non deducible:
template <typename T> struct identity { using type = T; };
template <typename T> using non_deducible_t = typename identity<T>::type;
And then
template<int RepeatTimes, class ... mutrArgs>
void run(
std::vector<int>& vec,
const std::function<void(int&, non_deducible_t<mutrArgs> ...)>& mutr,
non_deducible_t<mutrArgs> ... args
)
Demo
Even if in your case a simple typename F as suggested by Joachim Pileborg seems better.
If you look at all standard library algorithm function, at least the ones taking a "predicate" (a callable object) they take that argument as a templated type.
If you do the same it will build:
template<int RepeatTimes, typename F, class ... mutrArgs>
void run(
vector<int>& vec,
F mutr,
mutrArgs ... args
)
{
...
}
See here for an example of you code. Note that you don't need to provide all template arguments, the compiler is able to deduce them.
The code below is a minimal example of my problem. I created a simple template class containing a fixed-size array, and overloaded the assignment operator to accept any class defining the methods size() and begin() (eg, initializer_lists). I don't understand why g++ is not able to resolve my call to this operator (I'm using gcc 4.6):
***.cpp: In function ‘int main()’:
***.cpp:46:22: error: no match for ‘operator=’ in ‘a = {42, -1.0e+0, 3.14158999999999988261834005243144929409027099609375e+0}’
***.cpp:46:22: note: candidates are:
***.cpp:23:8: note: template<class U> A<T, N>::self& A::operator=(const U&) [with U = U, T = double, unsigned int N = 3u, A<T, N>::self = A<double, 3u>]
***.cpp:8:7: note: A<double, 3u>& A<double, 3u>::operator=(const A<double, 3u>&)
***.cpp:8:7: note: no known conversion for argument 1 from ‘<brace-enclosed initialiser list>’ to ‘const A<double, 3u>&’
***.cpp:8:7: note: A<double, 3u>& A<double, 3u>::operator=(A<double, 3u>&&)
***.cpp:8:7: note: no known conversion for argument 1 from ‘<brace-enclosed initialiser list>’ to ‘A<double, 3u>&&’
The first candidate is listed correctly, but there is no error message associated. Here is the code:
#include <iostream>
#include <algorithm>
#include <initializer_list>
// ------------------------------------------------------------------------
template <typename T, unsigned N>
class A
{
public:
typedef A<T,N> self;
// Default ctor
A() {}
// Copy ctor
template <typename U>
A( const U& other ) { operator=(other); }
// Assignemnt
template <typename U>
self& operator= ( const U& other )
{
if ( other.size() == N )
std::copy_n( other.begin(), N, m_data );
return *this;
}
// Display contents
void print() const
{
for ( unsigned i = 0; i < N; ++i )
std::cout << m_data[i] << " ";
std::cout << std::endl;
}
private:
T m_data[N];
};
// ------------------------------------------------------------------------
int main()
{
A<double,3> a;
a = {42,-1.0,3.14159};
a.print();
}
Does anyone know why this might be ambiguous, or what I did wrong?
Note: Ideally, I would even like to replace the first two lines of my main by a single one A<double,3> a = {42,-1.0,3.14159}; but I'm not sure how, I currently get the following error:
***: In function ‘int main()’:
***:45:34: error: could not convert ‘{42, -1.0e+0, 3.14158999999999988261834005243144929409027099609375e+0}’ from ‘<brace-enclosed initialiser list>’ to ‘A<double, 3u>’
Unlike auto, where a braced-init-list is deduced as an initializer_list, template argument deduction considers it to be a non-deduced context, unless there exists a corresponding parameter of type initializer_list<T>, in which case the T can be deduced.
From §14.8.2.1/1 [temp.deduct.call] (emphasis added)
Template argument deduction is done by comparing each function template parameter type (call it P) with the type of the corresponding argument of the call (call it A) as described below. If removing references and cv-qualifiers from P gives std::initializer_list<P0> for some P0 and the argument is an initializer
list (8.5.4), then deduction is performed instead for each element of the initializer list, taking P0 as a function template parameter type and the initializer element as its argument. Otherwise, an initializer list argument causes the parameter to be considered a non-deduced context (14.8.2.5).
Thus the argument to your operator= is not deduced to be an initializer_list<double>. For the code to work, you must define an operator= that takes an initializer_list argument.
template <typename U>
self& operator= ( const std::initializer_list<T>& other )
{
if ( other.size() == N )
std::copy_n( other.begin(), N, m_data );
return *this;
}
A brace-enclosed initializer list does not necessarily have the type std::initializer_list<T>, so you need to specify that the assignment operator template expects an std::initializer_list:
template <typename U>
A& operator=(std::initializer_list<U> other )
{
if ( other.size() == N )
std::copy_n( other.begin(), N, m_data );
return *this;
}
or
A& operator=(std::initializer_list<double> other )
{
if ( other.size() == N )
std::copy_n( other.begin(), N, m_data );
return *this;
}
I must say, an assignment operator that silently fails if the sizes don't match doesn't seem like a great idea.
I'd say it's this:
A<double,3> a;
a = {42,-1.0,3.14159};
You are initializing a with default constructor, and then trying to use initializer list on already initialized object - which complains about lacking of appropriate operator= overload. Instead try:
A<double,3> a = {42,-1.0,3.14159};
EDIT:
You also didn't defined required constructor:
template <typename T, unsigned N>
class A
{
public:
A(std::initializer_list list) : m_data(list) {}
//...
}