I want to get the active value in a std::variant without knowing which one is active. I thought i could write a template visitor and use std::visit but it doesn't work.
#include <variant>
#include <string>
#include <iostream>
struct Visit_configuration {
template<typename Data_type>
Data_type operator()(Data_type& t) const
{
return t;
}
};
int main()
{
std::variant<int, std::string> v;
v = "hello";
std::cout << std::visit(Visit_configuration(), v); // expect "hello"
std::cin.get();
}
MSVC doesn't compile and throws:
error C2338: visit() requires the result of all potential invocations
to have the same type and value category (N4741 23.7.7
[variant.visit]/2).
note: see reference to function template instantiation 'int
std::visit&,0>(_Callable
&&,std::variant &)' being compiled
So how to fix this?
edit: I want to use the obtained value maybe also for other so putting cout in the template isn't what im looking for.
Ask yourself the question:
What is the return type of std::visit if you don't know what part of the variant is active?
That is the question that the compiler must answer. And the answer can't be "it depends" - you (as in, the compiler) must decide on exactly one type at compile-time. The visit call cannot possibly return different types at runtime.
If you want to work with different types "at runtime", you must be in a function templated on the type you want to work with. In other words, there must be different functions (or function template instantiations) to handle the "write an int to cout" and "write a string to cout" cases. You cannot do this in the same (non-templated) function.
The straightforward solution here is thus to put the std::cout << into your templated visitor function - that's the point of visiting: Specifying what is supposed to happen in each case.
If you want to "use the obtained value maybe also for [some] other [purpose]", then that "other purpose" should also be part of the/a visitor. Only then can you have that "other purpose" handle the different cases at once (e.g. in a templated function). Otherwise you must decide at compile-time already which type shall be used - the compiler is not going to leave that choice open for later (run time).
Return type of visitor function should be identical.
Create printer visitor instead:
struct PrinterVisitor {
template<typename T>
void operator()(const T& t) const
{
std::cout << t;
}
};
int main()
{
std::variant<int, std::string> v;
v = "hello";
std::visit(PrinterVisitor{}, v); // expect "hello"
}
And in your case, you can even have lambda:
int main()
{
std::variant<int, std::string> v;
v = "hello";
std::visit([](const auto& t){std::cout << t;}, v); // expect "hello"
}
Related
I must be misunderstanding something because I thought the two cases are the same:
#include <iostream>
void function() { std::cout << "Hi\n"; }
int main()
{
std::vector<void(*)()> funcPtrVec;
std::vector<void()> funcVec;
funcPtrVec.push_back(function); // Works
funcVec.push_back(function); // Works
auto lambdaFunc = []() { std::cout << "Hi\n"; };
funcPtrVec.push_back(lambdaFunc); // Works
funcVec.push_back(lambdaFunc); // Doesn't work
}
Now, in both cases my compiler says that the function signatures are the same, void function() and void lambdaFunc(). I really thought that when a lambda function doesn't capture anything it behaves like a free function, which the same signatures would seem to support. Also, I guess I'm confused even more due to the fact that in the following all seem to be treated the same, as if decaying to the same thing:
void function() { std::cout << "Hi\n"; }
void funcTakingFunc(void()) {}
void funcTakingFuncPtr(void(*)()) {}
int main()
{
auto lambdaFunc = []() { std::cout << "Hi\n"; };
void(*funcPtr)() = lambdaFunc; // Works
funcTakingFuncPtr(lambdaFunc); // Works
funcTakingFuncPtr(funcPtr); // Works
funcTakingFunc(lambdaFunc); // Works
funcTakingFunc(funcPtr); // Works
// They all work
}
So as far as I can see the only distinction between the function and the function pointer made is when given as a template argument to vector. This obviously means I don't understand templates well, but what's the reason for this? Because the two really seem the same from the examples I tried.
std::vector<void()> is not allowed; the type must be an object type, and a function type is not an object type.
There are various parts of the specification of vector requirements we could identify as being violated by a non-object type; the most obvious is the default allocator. In the table in [allocator.requirements]/2 it is specified that the type the allocator is for must be an object type.
I have the following function template
template<typename T>
T foo(){
if(std::is_same<T,int>::value){
return 1;
}
if(std::is_same<T,std::string>::value){
return "Hello";
}
}
I want to apply it like this:
int main(){
std::cout << foo<int>() << std::endl; // 1
std::cout << foo<string>() << std::endl; // "Hello"
}
If I try to compile my template the compiler throws the following error:
error: cannot initialize return object of type 'int' with an lvalue of type 'const char [6]'.
If I remove the second if statement everything compiles fine and I get the correct output therefore I guess the comparison std::is_same<T,int>::value works as intended.
It seems like the Compiler detects the type of T, checks if all return statements match it and throws the error because an std::string is not implicitly castable to int.
Has anyone a solution or another workaround to satisfy my intention?
EDIT
To explain my intention: I am writing a wrapper class for a database cursor class. As these cursors are usually defined it has several member functions like getInt() or getString(). My idea was to implement a generic get<T>() that uses the corresponding cursor member function that depends on T.
Forget the if statements and fully specialize the template function:
template<>
int foo<int>(){
return 1;
}
template<>
std::string foo<std::string>(){
return "Hello";
}
When you reference foo<int>, the compiler generates a function like the following from your template:
int foo<int>(){
if(true){
return 1;
}
if(false){
return "Hello";
}
}
Above code is ill-typed, because (as the compiler tells you) an int cannot be initialized with a C string (char const [N]). Sure, the corresponding return statement will never be reached, but that's something to be figured out by "dead code elimination", which is merely an optimization.
The solution "now" is shown in Dustin's answer, with C++17 we'll get if constexpr which is able to discard code paths the way you expected it:
template<typename T>
T foo(){
if constexpr (std::is_same<T,int>::value){
return 1;
}
if constexpr (std::is_same<T,std::string>::value){
return "Hello";
}
}
Consider the following types:
#include <iostream>
typedef unsigned long long usize_t;
typedef unsigned __int16 uword_t;
typedef uword_t clockval_t; // time without seconds in format HHMM
std::string toString(clockval_t nClock)
{
return std::to_string((usize_t)nClock/100) + ":" + std::to_string((usize_t)nClock % 100);
}
std::string toString(uword_t nValue)
{
return std::to_string((usize_t)nValue);
}
void test(void)
{
uword_t val = 1;
clockval_t time = 1023; // 10:23
std::cout << "Value: " << toString(val);
std::cout << "time: " << toString(time);
}
Now when I try to compile this, I get an error from the compiler telling me that the std::string toString(clockval_t) already has a body. I understand why this happens of course, because the typedef is just an alias for uword_t.
AFAIK the only solutions are to provide a separate method:
std::string toClockString(clockval_t);
or make it an object:
class clockval ...
Is this correct or is there some other way to make the compiler choose the correct overload?
Even if there were a way to make compiler choose correct version, do you realize how it would be error-prone? Luckily, there is no such way because typedef creates alias and nothing more.
I suggest that you convert it into class. If you provide proper constructor and conversion operator then you even don't need to change parts of code which make use of clockval_t:
class clockval_t {
public:
clockval_t(uword_t aValue) : value(aValue) {}
operator uword_t() const { return value; }
private:
uword_t value;
};
...
clockval_t time = 1023; // works fine
std::cout << time << std::endl; // works fine
std::cout << (time / 10) << std::endl; // works fine
Is this correct or is there some other way to make the compiler choose the correct overload?
Yes you're correct, you can't overload on typedef since it's simply an alias. As you rightly suggest, either rename the function or create a new type with class. Adding a fake parameter simply to change the function signature is usually a bad idea, renaming is clearer.
The meaning of typedef is defined in the standard as (7.1.3 The typedef specifier):
Within the scope of its declaration, a typedef-name is syntactically equivalent to a keyword and names the type associated with the identifier (...). A typedef-name is thus a synonym for another type. A typedef-name does
not introduce a new type (...).
Therefore the two functions are indeed ambiguous in regard to the type of input parameter. You need to distinguish the type (e.g. by using different type, e.g. a class or enum) or perhaps add a second parameter (maybe with a default value) indicating which kind type exactly is being passed in.
Link to original answer: https://softwareengineering.stackexchange.com/questions/254473/in-which-stage-of-compilation-is-typedef-resolved-by-the-compiler
I'm writing a little event manager class where I store some function pointers inside a vector. I use std::function<void(int)> as vector type, I tested inserting inside it lambdas and normal functions and it works:
void t(int p){
/*things*/
}
[...]
event.bind([](int p){/*things*/});
event.bind(t);
Now, (at a certain point I need to delete lambdas but not functions,) my question is:
Is it possible to distinguish lambdas from functions? If yes, how?
EDIT:
Since I clarified my doubts, this question becomes just what the title says
The real answer is: you don't want to do this. It defeats the point of type-erasing functors if you actually want to know the original type also in case of whatever. This just smells like bad design.
What you are potentially looking for is std::function::target_type. This is a way to pull out the underlying type_info of the target function that the function object is storing. Each type_info has a name(), which can be demangled. Note that this is a very deep rabbit hole and you're basically going to have to hard-code all sorts of weird edge-cases. As I've been doing thanks to Yakk's very loving help.
Different compilers mangle their lambda names differently, so this approach doesn't even resemble portability. Quick checking shows that clang throws in a $ while gcc throws {lambda...#d}, So we can attempt to take advantage of that by writing something like:
bool is_identifier(std::string const& id) {
return id == "(anonymous namespace)" ||
(std::all_of(id.begin(), id.end(),
[](char c){
return isdigit(c) || isalpha(c) || c == '_';
}) && !isdigit(id[0]));
}
bool is_lambda(const std::type_info& info)
{
std::unique_ptr<char, decltype(&std::free)> own {
abi::__cxa_demangle(info.name(), nullptr, nullptr, nullptr),
std::free
};
std::string name = own ? own.get() : info.name();
// drop leading namespaces... if they are valid namespace names
std::size_t idx;
while ((idx = name.find("::")) != std::string::npos) {
if (!is_identifier(name.substr(0, idx))) {
return false;
}
else {
name = name.substr(idx+2);
}
}
#if defined(__clang__)
return name[0] == '$';
#elif defined(__GNUC__)
return name.find("{lambda") == 0;
#else
// I dunno?
return false;
#endif
}
And then throw that in your standard erase-remove idiom:
void foo(int ) { }
void bar(int ) { }
long quux(long x) { return x; }
int main()
{
std::vector<std::function<void(int)>> v;
v.push_back(foo);
v.push_back(bar);
v.push_back(quux);
v.push_back([](int i) { std::cout << i << '\n';});
std::cout << v.size() << std::endl; // prints 4
v.erase(
std::remove_if(
v.begin(),
v.end(),
[](std::function<void(int)> const& f){
return is_lambda(f.target_type());
}),
v.end()
);
std::cout << v.size() << std::endl; // prints 3
}
No, not in general.
A std::function<void(int)> can store a function pointer to any function that can be called by passing a single rvalue int. There are an infinite number of such signatures.
The type of a lambda is an unique anonymous class for each declaration. Two distinct lambdas do not share any type relationship.
You can determine of a std::function<void(int)> stores a variable of a specific type, but in both the function pointer and lambda case there is an unbounded number of different types that can be stored in the std::function to consider. And you can only test for "exactly equal to a type".
You can access the type id information, but there is no portable representation there, and generally using that information for anything other than identity matching (and related) or debugging is a bad idea.
Now, a restricted version of the question (can you tell if a std::function<void(int)> contains a function pointer of type void(*)(int)) is easy to solve. But in general, doing so remains a bad idea: first, because it is delicate (code far away from the point you use it, like a subtle change to the function signature, can break things), and second, inspecting and changing your behavior based on the type stored in a std::function should only be done in extreme corner cases (usually involving updating your code from using void* style callbacks to std::function style callbacks).
Be it a function pointer or lambda, it ends up as a std::function<void(int)> in the vector. It is then std::function<void(int)>'s responsibility to manage the function pointer or lambda, not yours. That means, you just remove the std::function<void(int)>s you want from the vector. The destructor of std::function<void(int)> knows how to do things right. In your case, that would be doing nothing with function pointers and invoking the destructor of lambdas. std::function<void(int)> enables you to treat different things in a nice and uniform way. Don't misuse it.
NOTE: This answer presupposes that there is a finite, distinct number of function signatures that may be assigned as event handlers. It assumes that assigning any-old function with the wrong signature is a mistake.
You can use std::function::target to determine which ones are the function pointers and by process of elimination figure out which ones must be the lambdas:
void func1(int) {}
void func2(double) {}
int main()
{
std::vector<std::function<void(int)>> events;
events.push_back(func1);
events.push_back([](int){});
events.push_back(func2);
for(auto& e: events)
{
if(e.target<void(*)(int)>())
std::cout << "funcion int" << '\n';
else if(e.target<void(*)(double)>())
std::cout << "funcion double" << '\n';
else
std::cout << "must be lambda" << '\n';
}
}
This works because std::function::target returns a null pointer if the parameter type doesn't match.
Single variable example:
void func(int) {}
int main()
{
std::function<void(int)> f = func;
if(f.target<void(*)(int)>())
std::cout << "not a lambda" << '\n';
}
Here is a sample design code of what I want to achieve. Basically I wanna store handler functions for different handlerNames and these handler functions can be of variable arguments.
The handler functions should be called on events with the required arguments are passed with Script::Handle(...)
How can I achieve this? Maybe its possible with Variadic Templates?
class Script
{
public:
Script() { /* ... */ }
template<typename TFunction>
void AddHandler(const char *handlerName, TFunction &&function)
{
_handlerMap[handlerName] = std::move(function);
}
void Handle(const char *handlerName, ...)
{
_handlerMap[handlerName](...);
}
private:
typedef std::map<std::string, std::function<void()>> HandlerMapType;
HandlerMapType _handlerMap;
};
//Handler functions
handlerOne() { std::cerr << "One"; }
handlerTwo(std::string a1, int a2) { std::cerr << "Two"; }
handlerThree(bool a1) { std::cerr << "Three"; }
int main(int argc, char **argv)
{
Script script;
script.AddHandler("One", std::bind(&handlerOne));
script.AddHandler("Two", std::bind(&handlerTwo));
script.AddHandler("Three", std::bind(&handlerThree));
script.Handle("One");
script.Handle("Two, "string", 96);
script.Handle("Three", true);
script.Handle("Three", "what should happen here?"); //String passed instead of bool
}
Let me prefix by saying that this is not a trivial thing to do in C++. And I will go as far to say that you should consider whether this is really something you need in your use case. In your example, you are asking for genericism that you can't really use. You will in any case need to know the signature of the function you are calling to call it properly; in that case what purpose is served by putting them in a container?
Generally, you'd do something like this if you are writing a middle layer of code. In your example, this would be equivalent to writing code that enables another user to call Handle. A common concrete example of this is to write a factory where objects in the factory may be instantiated using different arguments. However, it can't really be "different" arguments, at least not without some crazy casting. The solution is to make all the functions take the same argument, but make the argument a dynamic type that can store whatever arguments you want:
using argument_type = std::unordered_map<std::string, boost::any>;
void print(const argument_type & arg) {
auto to_print = boost::any_cast<std::string>(arg["to_print"]);
std::cerr << to_print << std::endl;
}
void print_none(const argument_type & arg) {
std::cerr << "none" << std::endl;
}
using my_func_t = std::function<void(const argument_type &)>;
std::vector<my_func_t> v;
v.emplace_back(print);
v.emplace_back(print_none);
// create some argument_types, feed them to f.
The above is not code that has been tested, nor with a working main, but I think this should give you a sense of how you could accomplish what you want.
edit: I thought about it a bit more, and I decided to elaborate a bit more on the "crazy casting" way. I suppose it's not really more crazy, but I strongly prefer what I showed above. The alternative is to completely type erase the functions themselves, and pass the arguments using a variadic template.
void print(std::string to_print) {
std::cerr << to_print << std::endl;
}
void print_none() {
std::cerr << "none" << std::endl;
}
std::vector<boost::any> v;
v.emplace_back(std::function<void(std::string)>(print));
v.emplace_back(std::function<void(void)>(print_none));
template <typename ... Args>
void call(const std::vector & funcs, int index, Args... args) {
auto f = boost::any_cast<std::function<void(Args...)>>(funcs[index]);
f(std::forward<Args>(args)...);
}
// unsure if this will actually work
call(f, 0, std::string("hello"));
The code above is very fragile though, because the types you pass to call will be deduced against, and then the cast will try to cast to a std::function that matches that signature. That exact signature. I don't have a lot of confidence that this will work out; if it's a reference, vs value, vs rvalue, etc. Casting back to a different std::function than what you put in is undefined behavior.
In summary, I'd either try to avoid needing to do this entirely, or go with the first solution. It's much less fragile, and it's better to be upfront about the fact that you are erasing the signatures of these functions.