How to find the Type of a struct that is passed as an argument and the template arguments for a lambda function?

The question I have pertains to the type of the structs that are passed as a function argument into this function

1
2
3
4
5
6
7
8
9
10
11
12
13
14
template<class Arg>
Result operator()(Arg && arg) const
    {
    	if (std::is_same< std::decay_t<Arg>, Person>::value)
			std::cout<<"is Person. "<<std::is_same< std::decay_t<Arg>, Person>::value<<std::endl;
		else if (std::is_same< std::decay_t<Arg>, Dir>::value)
			std::cout<<"is Dir."<<std::is_same< std::decay_t<Arg>, Dir>::value<<std::endl;

    	arg.print();

    	std::cout<<"Arg && arg "<<std::endl;
        return func(std::forward<Arg>(arg));
    }


I have no trouble getting the function in the struct to print but I cannot
use std::is_same to show that the type is Person or Dir?

Another question I have is related to the part where the Lambda function is created with
make_forwarding_visitor<std::string>

Why doesn't the Lambda Function

auto visitor = make_forwarding_visitor<std::string>([](const auto& t){ return t.name();});

have two arguments given that the struct forwarding_visitor has two parameters?

template<class Result, class Func>
struct forwarding_visitor : boost::static_visitor<Result>



I can see the return type class Result is std::string but where is the Func type declared?

Is this the second parameter that's class Func?

([](const auto& t){ return t.name();});


The rest is the complete code with output


is std::string.1
Func && func 
Func&& f 
is Person. 1
return Jens
Arg && arg 
return Jens
Jens
is Dir.1
return Dir
Arg && arg 
return foo
foo


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
#include <iostream>
#include <string>
#include <type_traits>
#include <boost/variant.hpp>

struct Person
{
    std::string name() const
    {
    	std::cout<<"return Jens"<<std::endl;
    	return "Jens";
    }
    void print()
    {
    	std::cout<<"return Jens"<<std::endl;
    }
};
struct Dir
{
    std::string name() const
    {
    	std::cout<<"return foo"<<std::endl;
    	return "foo";
    }
    void print()
	{
		std::cout<<"return Dir"<<std::endl;
	}
};
template<class Result, class Func>
struct forwarding_visitor : boost::static_visitor<Result>
{
    Func func;
    forwarding_visitor(const Func& f):func(f)
    {
    	std::cout<<"const Func& f"<<std::endl;
    }
    forwarding_visitor(Func&& f):func(std::move(f))
    {
    	std::cout<<"Func&& f "<<std::endl;
    }
    template<class Arg>
    Result operator()(Arg && arg) const
    {
    	if (std::is_same< std::decay_t<Arg>, Person>::value)
			std::cout<<"is Person. "<<std::is_same< std::decay_t<Arg>, Person>::value<<std::endl;
		else if (std::is_same< std::decay_t<Arg>, Dir>::value)
			std::cout<<"is Dir."<<std::is_same< std::decay_t<Arg>, Dir>::value<<std::endl;

    	arg.print();

    	std::cout<<"Arg && arg "<<std::endl;
        return func(std::forward<Arg>(arg));
    }
};
template<class Result, class Func>
forwarding_visitor<Result, std::decay_t<Func> > make_forwarding_visitor(Func && func)
{
	if (std::is_same< Result, std::string>::value)
		std::cout<<"is std::string."<<std::is_same< Result, std::string>::value<<std::endl;
	else
		std::cout<<"Neither:"<<std::endl;

	std::cout<<"Func && func "<<std::endl;
    return {std::forward<Func>(func)};
}
int main()
{
   using variant = boost::variant<Person,Dir>;
   variant p = Person{};
   variant d = Dir{};
   auto visitor = make_forwarding_visitor<std::string>([](const auto& t){ return t.name();});

   std::cout << boost::apply_visitor(visitor,p) << "\n";
   std::cout << boost::apply_visitor(visitor,d) << std::endl;
}
You need constexpr:
1
2
3
4
5
6
7
8
9
10
11
12
13
template<class Arg>
Result operator()(Arg && arg) const
    {
    	if constexpr (std::is_same< std::decay_t<Arg>, Person>::value)
			std::cout<<"is Person. "<<std::is_same< std::decay_t<Arg>, Person>::value<<std::endl;
		else if constexpr (std::is_same< std::decay_t<Arg>, Dir>::value)
			std::cout<<"is Dir."<<std::is_same< std::decay_t<Arg>, Dir>::value<<std::endl;

    	arg.print();

    	std::cout<<"Arg && arg "<<std::endl;
        return func(std::forward<Arg>(arg));
    }
Note that the type is determined at compile time not run time

Why doesn't the Lambda Function
auto visitor = make_forwarding_visitor<std::string>([](const auto& t){ return t.name();});
have two arguments given that the struct forwarding_visitor has two parameters?

It does have two arguments. The first one is std::string, and the second one is chosen by the compiler following a process called "function template argument deduction".

I have no trouble getting the function in the struct to print but I cannot use std::is_same to show that the type is Person or Dir?

This is because Arg is Person& and Dir&, explaining why you need decay_t
It does have two arguments. The first one is std::string, and the second one is chosen by the compiler following a process called "function template argument deduction".


Where exactly is it in the code where the compiler deduces the second parameter or where is the second parameter declared initially?

Is it this, const auto& t inside the Lambda declaration?

Just want to make sure I understand it.

Is this line a function pointer?

make_forwarding_visitor<std::string>(...);
because Lambdas usually start with square brackets []...

Just for reference I got this code from here

https://www.meetingcpp.com/blog/items/boostvariant-and-a-general-generic-visitor-class.html
Last edited on
The second template argument to make_forwarding_visitor is deduced from the first (and only) function argument.



auto visitor = make_forwarding_visitor<std::string, ...>([](const auto& t){ return t.name();}); 
                                                     ^   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
                                                     |                    |
                                                     | The compiler sees  |
                                                     | the type of the    |
                                                     | lambda expression  |
                                                     | and uses it to     |
                                                     | deduce the         |
                                                     | template argument. |
                                                     |____________________|

Last edited on
thanks for all the help
Registered users can post here. Sign in or register to post.