Strange use of void in c++ code - c++

Here is some code from a presentation about async tasks in C++
template <class T> class Future<T>{
//something
void foo(std::function<void(T)> cb);
//something
};
What does void(T) mean?

What does void(T) mean?
That specifies a function type; specifically, a function taking a single parameter of type T, and returning nothing. In general, type specifiers for complex types look like their corresponding variable declarations, but without a variable name:
void f(T); // declare a function
void(T) // specifier for a function type
int a[42]; // declare an array
int[42] // specifier for an array type
In this case, the function type is used to specify the signature of the function-call operator of the std::function:
void operator()(T);
so that the function object can be used like a function with that type:
T some_t;
cb(some_t); // usable like a function taking `T`

cb is a std::function whose operator() takes a T and returns void.

void(T) is a function signature (type)
Note the signature is not a pointer to a function, not a pointer to a member function and no lambda:
#include<functional>
void a(int) {}
struct B {
void f(int) {}
};
int main() {
std::function<void(int)> fn;
fn = a;
B b;
fn = std::bind(&B::f, b, std::placeholders::_1);
auto lambda = [](int) {};
fn = lambda;
}

The explanation can be as follows based on the C++11 specifications : A parameter list consisting of a single unnamed parameter of non-dependent type void is equivalent to an empty parameter list.
void is not a valid argument type for a function, however T in void(T) is a dependent type, it depends on a template parameter. That way you can have no arguments in the function based on the parameter of the template.

Related

Default lambda as templated parameter of a function

Consider the following code
template<bool b, typename T> void foo(const T& t = []() {}) {
// implementation here
}
void bar() {
foo<true>([&](){ /* implementation here */ }); // this compiles
foo<true>(); // this doesn't compile
}
In the case that doesn't compile I get the following errors:
error C2672: 'foo': no matching overloaded function found
error C2783: 'void foo(const T&)': could not deduce template argument for 'T'
I think it's clear what I want to achieve: let foo be called with and without a client-provided lambda. The compiler is MSVC++2017 version 15.4.4 toolset v141.
Default function arguments are not part of the template argument deduction process. To quote [temp.deduct.partial]/3:
The types used to determine the ordering depend on the context in
which the partial ordering is done:
In the context of a function call, the types used are those function parameter types for which the function call has arguments.
141
141) Default arguments are not considered to be arguments in this
context; they only become arguments after a function has been
selected.
That bullet and note indicate that since you didn't provide an argument for t in the call to foo, the type T cannot be deduced. The default lambda argument can only be taken into account if the function is selected to be called, not before.
The solution, as all the others have noted, is to provide an overload without parameters, that will call the templated one with the default lambda you have in mind.
Another (very efficient) way - default T to be a null functor.
// no_op is a function object which does nothing, regardless of how many
// arguments you give it. It will be elided completely unless you compile with
// -O0
struct no_op
{
template<class...Args>
constexpr void operator()(Args&&...) const {}
};
// foo defaults to using a default-constructed no_op as its function object
template<bool b, typename T = no_op> void foo(T&& t = T())
{
// implementation here
t();
}
void bar() {
foo<true>([&](){ std::cout << "something\n"; }); // this compiles
foo<true>(); // this now compiles
}
The compiler uses the arguments passed to deduce the template type. If there's no arguments, then how would the compiler be able to deduce the template type?
You can use overloading instead of default arguments here.
The overloaded non-argument function can simply call the function with the "default" argument:
template<bool b, typename T> void foo(const T& t) {
// implementation here
}
template<bool b> void foo() {
foo<b>([]() {});
}
Consider overloading it directly:
template <bool b>
void foo(void) {
foo([](){});
}
See CppReference:
Non-deduced contexts
4) A template parameter used in the parameter type of a function parameter that has a default argument that is being used in the call for which argument deduction is being done:
Type template parameter cannot be deduced from the type of a function default argument:
template void f(T = 5, T = 7);
void g()
{
f(1); // OK: calls f<int>(1, 7)
f(); // error: cannot deduce T
f<int>(); // OK: calls f<int>(5, 7)
}
You are trying to say something that makes no sense. You are asking the compiler to guess T from your arguments, but then you do not provide any argument.
The following code does compile, and does what you want:
template<bool b, typename T> void foo(const T& t) {
// implementation here
}
template<bool b> void foo() {
foo<b>([]() {}); // Call actual implementation with empty lambda
}
void bar() {
foo<true>([&](){ /* implementation here */ }); // this compiles
foo<true>(); // this now compiles as well
}

dynamic cast a reference and auto

I've encountered a pretty weird behavior when using auto and dynamic_cast.
This is the class hierachy i have:
class BaseInterface {
public:
virtual void someMethod()=0;
};
class Derived:public BaseInterface {
public:
virtual void someMethod1()=0;
void someMethod()override;
};
And of course there are some classes that implement all derived methods.
Then there is a third class which looks like this:
class ThirdClass {
public:
void demoMethod(BaseInterface&);
void anotherMethod(Derived&);
};
void ThirdClass::demoMethod(BaseInterface& obj) {
auto buffer=dynamic_cast<Derived&>(obj);
anotherMethod(buffer);
}
When i compile this with gcc i get an "cannot allocate an object of abstract type" error. Whereas when i replace
auto buffer=...
with
Derived& buffer=...
everything compiles fine. Why is that the case? Is auto not deducing the right type or something?
Also i found a dirty trick to still use auto:
void ThirdClass::demoMethod(Base& obj) {
auto buffer=dynamic_cast<Derived*>(&obj);
anotherMethod(*buffer);
}
You're getting Derived from auto. Use this instead:
auto & buffer = dynamic_cast<Derived&>(obj);
§7.1.6.4/7:
When a variable declared using a placeholder type is initialized […]
the deduced return type or variable type is determined from the type
of its initializer. […] let T be the declared type of the variable
or return type of the function. If the placeholder is the auto
type-specifier, the deduced type is determined using the rules for
template argument deduction. […] obtain P from T by replacing the
occurrences of auto with either a new invented type template
parameter U[…]. Deduce a value for U using the rules of template
argument deduction from a function call (14.8.2.1), where P is a
function template parameter type and the corresponding argument is the
initializer.
So, in order to familiarize yourself with the process, take a look at the actual rule used for deducing the type of buffer: What happens if you change
template <typename U>
void f( U );
to
void f( Derived& );
when calling f with an lvalue of type Derived? Clearly, for the function template, U will be deduced as Derived, which then yields a deduction failure.
This directly corresponds to the deduction of the placeholder type in your example - auto will be replaced by Derived, and that fails, as Derived is abstract.
Generally speaking, if you write
auto obj = …;
obj will never be a reference, just as U will never be deduced as a reference type when calling the above function template.
Instead, use auto&:
auto& buffer = dynamic_cast<Derived&>(obj);
Now, P is U&:
template <typename U>
void f(U&);
U is, of course, still deduced as Derived, but the type of P - which is effectively the type of buffer - is Derived&.

Why does this typedef allow me to use a base class pointer-to-member-function in this template?

If I attempt to compile the following code in MSVC:
template <typename DELEGATE>
void newButton(DELEGATE *obj, int (DELEGATE::*method)(int))
{
std::function<int(int)> callback = std::bind(
method, obj, std::placeholders::_1);
// ...
}
class Base
{
public:
virtual int test(int f) { return f * f; }
};
class Derived : public Base
{
};
int main()
{
Derived d;
newButton(&d, &Base::test);
}
I get a compiler error:
'void newButton(DELEGATE *,int (__thiscall DELEGATE::* )(int))' :
template parameter 'DELEGATE' is ambiguous
could be 'Base'
or 'Derived'
This is reasonable. The template expects an identical type for obj and method, but they are not exactly the same.
BUT, if I replace the pointer-to-member-function declaration with this template struct typedef, it compiles!
template <typename DELEGATE>
struct ButtonAction
{
typedef int (DELEGATE::*Type)(int);
};
template <typename DELEGATE>
void newButton(DELEGATE *obj, typename ButtonAction<DELEGATE>::Type method)
{
std::function<int(int)> callback = std::bind(
method, obj, std::placeholders::_1);
// ...
}
// rest same as before
Why? I would have expected the typedef to get resolved down to the exact same pointer-to-member-function type, and cause the same template error.
The reason is that in ButtonAction<DELEGATE>::Type, DELEGATE appears in a non-deduced context - the compiler cannot deduce DELEGATE from this, so it does not try. Therefore, the deduction is performed from the first argument only, and so it's unambiguous.
As to why DELEGATE cannot be deduced in this context - try to imagine what the process would need to be: inspect ButtonAction<T> for every possible type T and compare its nested typedef Type against the argument type. And note that there are infinitely many possible types.
A rule of thumb is: everything to the left of :: is a non-deduced context.
In the second example, the method parameter does not participate in type deduction, so DELEGATE is deduced to Derived, and &Base::test is implicitly converted to (Derived::*)(int).

function-pointers and class-templates

I have a template class CFoo using the following types
enum My_Types {t1,t2};
with the specialization given by
template<My_Types T>
class CFoo
{
public:
CFoo()
{
std::cerr<<"ERROR:....";
exit(1);
}
};
template<>
class CFoo<t1>
{
....
};
In addition I have a function which uses a CFoo object as an argument
template<class T>
void foo1 ( const T &CfooObj,...);
Now I need a pointer to foo1, so I have to specify the template argument
void (*foo1_pointer) ( const CFoo< t1 >&,...);
But the following seems not to be correct (" no matches converting function foo1..."):
foo1_pointer=&foo1;
How to pass the pointer of this template function correctly?
This is probably due to the old version of your GCC compiler. This code compiles fine on GCC 4.7.2, Clang 3.2, ICC 13.0.1, and VS10:
#include <iostream>
enum My_Types {t1,t2};
template<My_Types T>
class CFoo { /* ... */ };
template<> class CFoo<t1> { /* ... */ };
template<class T>
void foo1 (const T &, ...) { /* ... */ }
int main()
{
void (*foo1_pointer) (const CFoo< t1 >&, ...);
foo1_pointer = &foo1;
}
The compiler should be able to deduce the template arguments of foo1 when taking its address from the type of the function pointer it is assigned to. Per Paragraph 14.8.2.3/1 of the C++11 Standard:
Template arguments can be deduced from the type specified when taking the address of an overloaded function (13.4). The function template’s function type and the specified type are used as the types of P and A, and the deduction is done as described in 14.8.2.5.
And also, per Paragraph 13.4/1:
A use of an overloaded function name without arguments is resolved in certain contexts to a function, a pointer to function or a pointer to member function for a specific function from the overload set. A function template name is considered to name a set of overloaded functions in such contexts. The function selected is the one whose type is identical to the function type of the target type required in the context. [...]
The assignment should be like this:
foo1_pointer = &foo1<CFoo<t1>>;
You can just write foo1<CFoo<t1>>. Or just foo1 (works with g++ 4.7.2).

Deduce template argument from std::function call signature

Consider this template function:
template<typename ReturnT>
ReturnT foo(const std::function<ReturnT ()>& fun)
{
return fun();
}
Why isn't it possible for the compiler to deduce ReturnT from the passed call signature?
bool bar() { /* ... */ }
foo<bool>(bar); // works
foo(bar); // error: no matching function call
A function pointer of type bool (*)() can be converted to std::function<bool()> but is not the same type, so a conversion is needed. Before the compiler can check whether that conversion is possible it needs to deduce ReturnT as bool, but to do that it needs to already know that std::function<bool()> is a possible conversion, which isn't possible until it deduces ReturnT ... see the problem?
Also, consider that bool(*)() could also be converted to std::function<void()> or std::function<int()> ... which should be deduced?
Consider this simplification:
template<typename T>
struct function
{
template<typename U>
function(U) { }
};
template<typename T>
void foo(function<T>)
{ }
int main()
{
foo(1);
}
How can the compiler know whether you wanted to create function<int> or function<char> or function<void> when they can all be constructed from an int?
std::function<bool()> bar;
foo(bar); // works just fine
C++ can't deduce the return type from your function bar because it would have to know the type before it could find all the constructors that take your function pointer.
For example, who's to say that std::function<std::string()> doesn't have a constructor taking a bool (*)()?
The function bar is of type bool (*)() or so, that is: a normal pre-C++11 function type. I'm not that confident in C++11, but I guess the compiler does not see the connection between bool (*)() and const std::function<ReturnT()>&, even when the first can be implicitly converted into the second for ReturnT = bool.