I have this MCVE:
#include <stdio.h>
#include <atomic>
template<typename T> void assertVariableHasBeenSet( T, const char * );
template<> void assertVariableHasBeenSet<std::atomic<double> &>
( std::atomic<double> & myDouble,
const char * variableName
)
{
printf( "Double:%s=%f\n", variableName, myDouble.load() );
};
int main()
{
std::atomic<double> myDoubleAtomic {23.45};
assertVariableHasBeenSet( myDoubleAtomic, "myDoubleAtomic" );
}
I get this compiler error:
getType.cpp: In function ‘int main()’:
getType.cpp:14:61: error: use of deleted function ‘std::atomic<_Tp>::atomic(const std::atomic<_Tp>&) [with _Tp = double]’
assertVariableHasBeenSet( myDoubleAtomic, "myDoubleAtomic" );
^
In file included from getType.cpp:2:0:
/usr/local/include/c++/4.9.4/atomic:169:7: note: declared here
atomic(const atomic&) = delete;
^
getType.cpp:4:27: error: initializing argument 1 of ‘void assertVariableHasBeenSet(T, const char*) [with T = std::atomic<double>]’
How can I pass a std::atomic<double> reference to the specialized template?
In a normal function it is possible.
For this case, T will be deduced as std::atomic<double>, not std::atomic<double> &. Then the primary template will always be invoked instead of the specialization.
You can specify the template argument explicitly, e.g.
assertVariableHasBeenSet<std::atomic<double> &>(myDoubleAtomic, "myDoubleAtomic");
Or apply overloading.
template<typename T> void assertVariableHasBeenSet( T, const char * );
void assertVariableHasBeenSet( std::atomic<double> & myDouble,
const char * variableName
)
{
printf( "Double:%s=%f\n", variableName, myDouble.load() );
}
Your issue is here:
template<typename T> void assertVariableHasBeenSet( T, const char * );
The primary template will be chosen because myDoubleAtomic is of type std::atomic<double>, not std::atomic<double> &.
The primary template tries to pass T by value, requiring a copy. std::atomic has a deleted copy constructor resulting in that error.
You should tell the compiler what type to use explicitly :
assertVariableHasBeenSet<std::atomic<double> &>(myDoubleAtomic, "myDoubleAtomic" );
The first thing to happen is overload resolution. During overload resolution the type T is deduced as std::atomic<double>. Next the proper specialisation is determined. There is no specialised version and the primary template is used. The specialisation for std::atomic<double>& will never be found by deduction.
There are two approaches to fix the problem (I don’t consider specifying the type explicitly a solution):
Declare the primary template to take a forwarding reference T&& as this would deduce T as std::atomic<double>&.
Instead of template specialisation use overloading, i.e., remove the template<> and the <std::atomic<double>&> after the function name.
Related
This C++ code doesn't compile, you get an error "candidate function template not viable: 1st argument ('const int32_t' (aka 'const int')) would lose const qualifier"
I know I can solve this by adding an overload for Func(const T& value), but I'm curious to learn why this doesn't compile?
template <typename T>
void Func(T&& value)
{
// Do stuff
}
struct Obj
{
int32_t Id{};
};
int main(int argc, char* argv[])
{
const Obj i{};
Func<int32_t>(i.Id);
}
When you make this call:
Func<int32_t>(i.Id);
you are specifying the template arguments. This means the T&& in Func is not considered a forwarding reference at all. Instead, it's just an rvalue-reference, which is int32_t&&. As the compiler says, binding int32_t && to a int32_t const & would discard the const qualifier, and the call doesn't compile.
On the other hand, if you don't specify the template argument:
Func(i.Id);
then the T&& is indeed a forwarding reference, which deduces int32_t const &, and the call compiles.
Sorry for the generic title, but I'm unable to focus the problem.
I have a templatized class method that accept an argument pack and provides a new type in return, to hide the details of the implementation. More specifically, the class handles SQLite queries, and the method calls sqlite3_prepare() to prepare the statement before executing the query.
class Table {
...
template <typename ...Ts>
class PreparedStatement { ... };
template <typename ...Ts>
PreparedStatement<Ts...> prepare(std::tuple<Ts...> tuple) {
// do something
return PreparedStatement<Ts...> ( ... );
}
That works well with "normal" types, but the problem occurs when the arguments are declared const:
const Field<int> fld = createField<int>("name");
...
PreparedStatement<decltype(fld)> s = prepare(make_tuple(fld));
The error is the following:
no match for 'operator =' (operand types are PreparedStatenent<const Field<int>> and PreparedStatement<Field<int>>
I suspect the issue is in my declaration of the function, is there a way to fix this issue and make the function more "elegant" ?
NOTE: I know I can fix the issue by manually declare the s variable, but my doubts are on how the method was implemented.
As Many Asked, here's an example:
#include <tuple>
template <typename T>
struct Field {
};
class Table {
public:
template <typename ...Ts>
class PreparedStatement {
public:
PreparedStatement() {};
};
template <typename ...Ts>
PreparedStatement<Ts...> prepare(std::tuple<Ts...> tuple) {
// do something
return PreparedStatement<Ts...> ( );
}
};
int main()
{
Field<int> fld;
Table t;
Table::PreparedStatement<decltype(fld)> p;
p = t.prepare(std::make_tuple(fld));
// here comes the problem
const Field<int> f2;
Table::PreparedStatement<decltype(f2)> p2;
p2 = t.prepare(std::make_tuple(f2));
return 0;
}
and here's the compiler output
main.cpp: In function 'int main()': main.cpp:35:39: error: no match
for 'operator=' (operand types are 'Table::PreparedStatement >' and 'Table::PreparedStatement >')
p2 = t.prepare(std::make_tuple(f2));
^ main.cpp:10:10: note: candidate: constexpr Table::PreparedStatement >&
Table::PreparedStatement >::operator=(const
Table::PreparedStatement >&)
class PreparedStatement {
^~~~~~~~~~~~~~~~~ main.cpp:10:10: note: no known conversion for argument 1 from 'Table::PreparedStatement >'
to 'const Table::PreparedStatement >&'
main.cpp:10:10: note: candidate: constexpr
Table::PreparedStatement >&
Table::PreparedStatement
::operator=(Table::PreparedStatement >&&) main.cpp:10:10: note: no known conversion for argument 1 from
'Table::PreparedStatement >' to
'Table::PreparedStatement >&&'
UPDATE
As many noted, I could use auto to deduce the type, but in some condition auto cannot practically be used. One is, for example, if I need to declare the statement in the Class Context.
So suppose auto is forbidden for some reason. Isn't any other solution available? See the updated code above.
cppreference.com for make_tuple tells us:
template< class... Types >
tuple<VTypes...> make_tuple( Types&&... args );
For each Ti in Types..., the corresponding type Vi in Vtypes... is
std::decay<Ti>::type unless application of std::decay results in
std::reference_wrapper<X> for some type X, in which case the deduced
type is X&.
While std::decay, among other things, removes cv-qualifiers. So your type will be no PreparedStatement<const Field<int>>, but PreparedStatement<Field<int>>.
You can use auto, as manni66 proposed, to avoid such problems.
auto s = prepare(make_tuple(fld));
I could use auto to deduce the type, but in some condition auto cannot practically be used. One is, for example, if I need to declare the statement in the Class Context. So suppose auto is forbidden for some reason. Isn't any other solution available? See the updated code above.
Instead of auto, you can use a decltype expression that take in count the value returned by prepare.
I mean... instead of
Table::PreparedStatement<decltype(f2)> p2;
you can try with
decltype(t.prepare(std::make_tuple(f2))) p2;
or
decltype(std::declval<Table>().prepare(
std::make_tuple(std::declval<Field<int>>()))) p2;
I suppose you can use a similar decltype() also to declare members of your classes.
Consider the following code:
#include <iostream>
#include <functional>
int main() {
auto run = [](auto&& f, auto&& arg) {
f(std::forward<decltype(arg)>(arg));
};
auto foo = [](int &x) {};
int var;
auto run_foo = std::bind(run, foo, var);
run_foo();
return 0;
}
Which gives the following compilation error when compiled with clang:
$ clang++ -std=c++14 my_test.cpp
my_test.cpp:6:9: error: no matching function for call to object of type 'const (lambda at my_test.cpp:8:16)'
f(std::forward<decltype(arg)>(arg));
^
/usr/bin/../lib64/gcc/x86_64-pc-linux-gnu/6.3.1/../../../../include/c++/6.3.1/functional:998:14: note: in instantiation of function template specialization 'main()::(anonymous class)::operator()<const (lambda at my_test.cpp:8:16) &, const int &>' requested here
= decltype( std::declval<typename enable_if<(sizeof...(_Args) >= 0),
^
/usr/bin/../lib64/gcc/x86_64-pc-linux-gnu/6.3.1/../../../../include/c++/6.3.1/functional:1003:2: note: in instantiation of default argument for 'operator()<>' required here
operator()(_Args&&... __args) const
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
my_test.cpp:11:12: note: while substituting deduced template arguments into function template 'operator()' [with _Args = <>, _Result = (no value)]
run_foo();
^
my_test.cpp:8:16: note: candidate function not viable: 1st argument ('const int') would lose const qualifier
auto foo = [](int &x) {};
^
my_test.cpp:8:16: note: conversion candidate of type 'void (*)(int &)'
1 error generated.
Why is arg deduced to be const int& instead of just int&?
std::bind documentation says:
Given an object g obtained from an earlier call to bind, when it is
invoked in a function call expression g(u1, u2, ... uM), an invocation
of the stored object takes place, as if by std::invoke(fd,
std::forward(v1), std::forward(v2), ...,
std::forward(vN)), where fd is a value of type std::decay_t the
values and types of the bound arguments v1, v2, ..., vN are determined
as specified below.
...
Otherwise, the
ordinary stored argument arg is passed to the invokable object as
lvalue argument: the argument vn in the std::invoke call above is
simply arg and the corresponding type Vn is T cv &, where cv is the
same cv-qualification as that of g.
But in this case, run_foo is cv-unqualified. What am I missing?
MWE:
#include <functional>
int main() {
int i;
std::bind([] (auto& x) {x = 1;}, i)();
}
[func.bind]/(10.4) states that the cv-qualifiers of the argument passed to the lambda are those of the argument to bind, augmented by the cv-qualifiers of the call wrapper; but there are none, and thus a non-const int should be passed in.
Both libc++ and libstdc++ fail to resolve the call. For libc++, reported as #32856, libstdc++ as #80564. The main problem is that both libraries infer the return type in the signature somehow, looking like this for libstdc++:
// Call as const
template<typename... _Args, typename _Result
= decltype( std::declval<typename enable_if<(sizeof...(_Args) >= 0),
typename add_const<_Functor>::type&>::type>()(
_Mu<_Bound_args>()( std::declval<const _Bound_args&>(),
std::declval<tuple<_Args...>&>() )... ) )>
_Result operator()(_Args&&... __args) const
During template argument deduction as necessitated by overload resolution, the default template argument will be instantiated, which causes a hard error due to our ill-formed assignment inside the closure.
This can be fixed by perhaps a deduced placeholder: remove _Result and its default argument entirely, and declare the return type as decltype(auto). This way, we also get rid of SFINAE which influences overload resolution and thereby induces incorrect behaviour:
#include <functional>
#include <type_traits>
struct A {
template <typename T>
std::enable_if_t<std::is_const<T>{}> operator()(T&) const;
};
int main() {
int i;
std::bind(A{}, i)();
}
This should not compile—as explained above, the argument passed to A::operator() should be non-const because i and the forwarding call wrapper are. However, again, this compiles under libc++ and libstdc++, because their operator()s fall back on const versions after the non-const ones fail under SFINAE.
I have encounter serious template type deduction problem when I use method pointer in argument of a template function.
Let's take the following code:
template <class ClassT, typename Arg1T>
inline void testTemplateFct(ClassT * clazz,
void (ClassT::*fctPtr)(Arg1T),
const Arg1T & arg1)
{
}
class TestClass
{
public:
void testMethodIntArg(int arg)
{}
void testMethodDoubleArg(double arg)
{}
void testMethodStringArg(const char * arg);
};
int main()
{
TestClass testClass;
testTemplateFct(&testClass,
&TestClass::testMethodIntArg,
10);
testTemplateFct(&testClass,
&TestClass::testMethodDoubleArg,
10.0);
/// BEGINNING OF MY PROBLEM
testTemplateFct(&testClass,
&TestClass::testMethodStringArg,
"a string...");
/// END OF MY PROBLEM
return 0;
}
If I compile it using g++, I get the following error message:
$ g++ ArgumentDeduction.cpp -o ArgumentDeduction
ArgumentDeduction.cpp: In function ‘int main()’:
ArgumentDeduction.cpp:42:18: error: no matching function for call to ‘testTemplateFct(TestClass*, void (TestClass::*)(const char*), const char [12])’
"a string...");
^
ArgumentDeduction.cpp:4:13: note: candidate: template<class ClassT, class Arg1T> void testTemplateFct(ClassT*, void (ClassT::*)(Arg1T), const Arg1T&)
inline void testTemplateFct(ClassT * clazz,
^~~~~~~~~~~~~~~
ArgumentDeduction.cpp:4:13: note: template argument deduction/substitution failed:
ArgumentDeduction.cpp:42:18: note: deduced conflicting types for parameter ‘const Arg1T’ (‘const char*’ and ‘char [12]’)
"a string...");
If I remove the reference of the third argument of method testTemplateFct the problem disappears (HOWEVER I ABSOLUTELY NEED THE REFERENCE IN ORDER TO AVOID COPY)
template <class ClassT, typename Arg1T>
inline void testTemplateFct(ClassT * clazz,
void (ClassT::*fctPtr)(Arg1T),
const Arg1T arg1)
{}
I understand more or less the error message but I do not understand why there is an ambiguity between const char* and char [12]. I do not understand why the problem disappears when I remove the reference.
Finally, I would strongly appreciate any help in order to correct this code while keeping the reference
PS: I know that I can "force" the type deduction by doing:
testTemplateFct(&testClass,
&TestClass::testMethodStringArg,
(const char *) "a string...");
but I don't like it very much
Your template requires that both the occurrences of Arg1T are deduced to the same type. I believe that is not what you want. Instead the types should be deduced independently:
template <class ClassT, typename Arg1T, typename GivenT>
inline void testTemplateFct(ClassT * clazz,
void (ClassT::*fctPtr)(Arg1T),
GivenT &&arg1)
{
//example use
(clazz->*fctPtr)(std::forward<GivenT>(arg1));
}
I do not understand why there is an ambiguity between const char* and char [12].
Note that "a string..." is an array with type const char[12]. For the function template testTemplateFct, the parameter arg1 is declared as a reference, i.e. const Arg1T &, then array-to-pointer decay won't occur in template argument deduction and Arg1T is deduced as char[12], which doesn't match the deduced type of Arg1T from the 2nd argument, i.e. const char*, so deduction failed.
I do not understand why the problem disappears when I remove the reference.
When the parameter is declared as pass-by-value array-to-pointer decay is applied; then both the deduced type of Arg1T from the 2nd and 3rd argument will be const char* and everything work fine.
You have two basic options.
The first one is to change your invocation to:
testTemplateFct(&testClass,
&TestClass::testMethodStringArg,
(const char *)"a string...");
The second option is to add an overload:
template <class ClassT, size_t n>
inline void testTemplateFct(ClassT * clazz,
void (ClassT::*fctPtr)(const char *),
const char (&arg1)[n])
{
testTemplateFct<ClassT, const char *>(clazz, fctPtr, arg1);
}
Pick which one works best for you.
A literal character string is actually a const char[n], and not a const char *. The const char array decays to a const char * in an ordinary function call; but this decay does not occur as part of template deduction; hence the problem.
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.