# Issue

I have a boost::variant and I would like to execute a functor only if the variant is of a special type, so I made up this function:

```
template<typename T, typename Variant>
void if_init(Variant& opt_variant, std::function<void(T)> functor){
if(auto* ptr = boost::get<T>(&opt_variant)){
functor(*ptr);
}
}
```

This works well, but I would like the type T to be deduced, so that I can write that:

```
if_init(b, [](double var){ std::cout << "I'm double and set" << std::endl; });
```

But the type is not deduced:

```
type_inference.cpp:19:5: error: no matching function for call to 'if_init'
if_init(b, [](double var){ std::cout << "I'm double and set" << std::endl; });
^~~~~~~
type_inference.cpp:10:6: note: candidate template ignored: failed template argument deduction
void if_init(Variant& opt_variant, std::function<void(T)> functor){
```

If I write:

```
if_init<double>(b, [](double var){ std::cout << "I'm double and set" << std::endl; });
```

it works well.

Is there a way to have type T being deduced ? I would like to type T only once. Here the type is short, but in the real case, there are long types.

I'm using CLang 3.2.

Here is the full test case (the first call compiles not the second):

```
#include <iostream>
#include <functional>
#include <boost/variant.hpp>
typedef boost::variant<int, double> Test;
template<typename T, typename Variant>
void if_init(Variant& opt_variant, std::function<void(T)> functor){
if(auto* ptr = boost::get<T>(&opt_variant)){
functor(*ptr);
}
}
int main(){
Test b = 1.44;
if_init<double>(b, [](double var){ std::cout << "I'm double and set" << std::endl; });
if_init(b, [](int var){ std::cout << "I'm int and set" << std::endl; });
return 0;
}
```

# Solution

I recommend you think of `std::function<Sig>`

as a container of any one functor that conforms to `Sig`

as a signature -- and which can be replaced at any moment. This functionality comes in very handy for e.g. `std::vector<std::function<Sig>>`

because such a container can then hold functors of *different* types.

In your case, because you only care to have just the one functor you really don't need the functionality of `std::function<Sig>`

. As such, I recommend you declare your function template like so:

```
template<typename T, typename Variant, typename Functor>
void if_init(Variant& opt_variant, Functor functor);
```

If you are worried that this doesn't communicate that `Functor`

must conform to a `void(T)`

signature, please note that `std::function<Sig>`

does *not* enforce that either: although obviously you *will* end up with a compilation error, it is not a nice one. It's planned to be changed (and maybe your implementation has that either), but changed to a different kind of error. Still not that helpful for your case.

I personally make use of template aliases (in the template parameter list) to both document and enforce what a functor should conform to. This ends up looking like:

```
// Documents that e.g. long l = std::forward<Functor>(functor)(42.)
// should be a valid expression -- a functor that returns int would
// also be accepted.
// Triggers a hard-error (typically a static_assert with a nice message)
// on violation.
template<typename Functor, Requires<is_callable<Functor, long(double)>>...>
R foo(Functor functor);
// Documents that this function template only participates in overload resolution
// if the functor conforms to the signature.
// Does not trigger a hard-error (necessary by design); if everything goes right
// then another overload should be picked up -- otherwise an error of the kind
// 'no matching overload found' is produced
template<typename Functor, EnableIf<is_callable<Functor, long(double)>>...>
R bar(Functor functor);
```

As to your *exact* question, the rules of C++ do not allow for a template parameter to be deduced in your case. It's really not an easily fixed 'problem', if it is one. You can find more information on this.

Answered By - Luc Danton Answer Checked By - Terry (PHPFixing Volunteer)

## 0 Comments:

## Post a Comment

Note: Only a member of this blog may post a comment.