Perfect forwarding to function pointer call - c++

I'm trying to compile simple templetized wrapper in Visual Studio 2015
template<typename Rv, typename ...Args>
Rv call(Rv(*fp)(Args...), Args&&...args) {
return (*fp)(std::forward<Args>(args)...);
}
int iArg;
void(*fn)(int);
call(fn, iArg);`
I'm getting the following compiler error:
test.cpp(30): error C2672: 'call': no matching overloaded function found
error C2782: 'Rv call(Rv (__cdecl *)(Args...),Args &&...)': template parameter 'Args' is ambiguous
1> test.cpp(22): note: see declaration of 'call'
1> test.cpp(30): note: could be 'int'
1> test.cpp(30): note: or 'int&'
Why?
Thanks in advance

You have to split args to allow correct deduction:
template <typename Rv, typename... Args, typename... Ts>
Rv call(Rv(*fp)(Args...), Ts&&...args) {
return (*fp)(std::forward<Ts>(args)...);
}

This can be made a bit more generic to call any type of callable thing by having the template parameter be a function type instead of a raw function pointer. Working example for GCC. Should work for visual studio.
#include <iostream>
#include <type_traits>
template<typename Func, typename ...Args>
typename std::result_of<Func(Args...)>::type call(Func fp, Args&&...args) {
return fp(std::forward<Args>(args)...);
}
void foo(int i) {
std::cout << i << std::endl;
}
int main() {
int iArg = 2;
void(*fn)(int) = foo;
call(fn, iArg);
return 0;
}

Related

Changing std::async to use function pointer instead of lambda

tl;dr:
Working version: https://godbolt.org/z/fsxEeGf6W
Broken version (why?): https://godbolt.org/z/KoooxsqoW
I am writing a utility function that wraps std::async while catching all exceptions.
#include <functional>
#include <future>
#include <iostream>
#include <string>
#include <thread>
namespace Async {
namespace detail {
template <typename F, typename... Args>
std::invoke_result_t<F, Args...> RunWithLogging(std::string label, F&& f,
Args&&... args) {
try {
return std::invoke(std::forward<F>(f), std::forward<Args>(args)...);
} catch (std::exception& ex) {
std::cout << label << "Exception escaped thread \"" << label
<< "\": " << ex.what();
throw;
} catch (...) {
std::cout << label << "Exception escaped thread \"" << label
<< "\": (non-standard exception type)";
throw;
}
}
} // namespace detail
/// Like std::async(std::launch::async, f, args...):
/// - Catches and logs any escaped exceptions
/// - Returned future joins the thread on destructor
template <typename F, typename... Args>
[[nodiscard]] std::future<std::invoke_result_t<F, Args...>> Launch(
std::string label, F&& f, Args&&... args) {
return std::async(
std::launch::async, [label = std::move(label), f = std::forward<F>(f),
... args = std::forward<Args>(args)]() mutable {
return detail::RunWithLogging(std::move(label), std::forward<F>(f),
std::forward<Args>(args)...);
});
}
} // namespace Async
Instead of that double-forwarding mutable lambda, I thought I could save a few lines and just use a function pointer using async's parameter-passing signature:
template <typename F, typename... Args>
[[nodiscard]] std::future<std::invoke_result_t<F, Args...>> Launch(
std::string label, F&& f, Args&&... args) {
return std::async(std::launch::async, &detail::RunWithLogging,
std::move(label), std::forward<F>(f),
std::forward<Args>(args)...);
;
}
This doesn't compile, for these reasons:
C:\...\lib\Async\Thread.h(33,15): error C2672: 'async': no matching overloaded function found [C:\...\build\lib\Async\AsyncTest.vcxproj]
C:\Program Files\Microsoft Visual Studio\2022\Professional\VC\Tools\MSVC\14.34.31933\include\future(1535,81): message : could be 'std::future<_Select_invoke_traits<decay<_Ty>::type,decay<_ArgTypes>::type...>::type> std::async(_Fty &&,_ArgTypes &&...)' [C:\...\build\lib\Async\AsyncTest.vcxproj]
C:\...\lib\Async\Thread.h(33,15): message : 'std::future<_Select_invoke_traits<decay<_Ty>::type,decay<_ArgTypes>::type...>::type> std::async(_Fty &&,_ArgTypes &&...)': could not deduce template argument for '_ArgTypes &&' from 'overloaded-function' [C:\...\build\lib\Async\AsyncTest.vcxproj]
C:\Program Files\Microsoft Visual Studio\2022\Professional\VC\Tools\MSVC\14.34.31933\include\future(1522,81): message : or 'std::future<_Select_invoke_traits<decay<_Ty>::type,decay<_ArgTypes>::type...>::type> std::async(std::launch,_Fty &&,_ArgTypes &&...)' [C:\...\build\lib\Async\AsyncTest.vcxproj]
C:\...\lib\Async\Thread.h(32,47): message : 'std::future<_Select_invoke_traits<decay<_Ty>::type,decay<_ArgTypes>::type...>::type> std::async(std::launch,_Fty &&,_ArgTypes &&...)': could not deduce template argument for '_Fty' [C:\...\build\lib\Async\AsyncTest.vcxproj]
C:\...\lib\Async\ThreadTest.cpp(24,57): message : see reference to function template instantiation 'std::future<int> Async::Launch<int(__cdecl *)(int),int>(std::string,F &&,int &&)' being compiled [C:\...\build\lib\Async\AsyncTest.vcxproj]
with
[
F=int (__cdecl *)(int)
]
What am I doing wrong? I've tried:
Adding std::decay_t<> to a invoke_result_t<...>'s parameters
Explicitly specifying the template args for RunWithLogging
&detail::RunWithLogging or detail::RunWithLogging
Using auto return types
I believe that the issue lies with references not being passed to threads and with the function argument to std::async not being fully specialized. I made the following changes.
I specialized detail::RunWithLogging and passed label by value:
return std::async(std::launch::async, &detail::RunWithLogging<F,Args...>,
label, std::forward<F>(f),
std::forward<Args>(args)...);
Then I added std::ref to the lambda function.
auto lambda = [](int a, int b) { return a + b; };
auto f = Async::Launch("Lambda", std::ref(lambda), 1, 2);
EXPECT_EQ(f.get(), 3);
And finally I wrapped hi with std::ref, which fixed all compilation issues.
std::string hi = "hello";
auto f =
Async::Launch("SomethingWithConstRef", &SomethingWithConstRef, std::ref(hi));
EXPECT_EQ(f.get(), "hello!");
Lambdas are nice because they capture references without needing to use std::ref.
See this other post for more information.

SFINAE constexpr error in Microsoft Visual C++

Simple SFINAE code using constexpr fails to compile. The same code compiles in g++.
This issue comes only when constexpr is used. While using std::is_integral_v<T>, it compiles.
// test code
#include<iostream>
template<typename T>
constexpr inline bool is_integral() {
return std::is_integral_v<T>;
}
template<typename T>
constexpr inline bool is_floating_point() {
return std::is_floating_point_v<T>;
}
struct tester {
template<typename T>
std::enable_if_t<is_integral<T>(), void> operator()(int* p){
//integral version
std::cout<<"integral\n";
}
template<typename T>
std::enable_if_t<is_floating_point<T>(), void> operator()(int* p){
//floating point version
std::cout<<"floating\n";
}
template <typename T, typename... Args>
std::enable_if_t<!is_integral<T>() && !is_floating_point<T>(), void> operator()(Args&&...)
{
std::cerr<<"not supported.\n";
}
};
enum class type { INT, FLOAT, STRING};
void type_dispatcher(type tp) {
tester t;
switch(tp) {
case type::INT:
t.operator()<int>(nullptr);
break;
case type::FLOAT:
t.operator()<float>(nullptr);
break;
default:
std::cout<<"Unsupported\n";
}
}
int main() {
type t1{type::INT}, t2{type::FLOAT}, t3{type::STRING};
type_dispatcher(t1);
type_dispatcher(t2);
type_dispatcher(t3);
return 0;
}
Error: cl.exe /std:c++17 ..\sfinae_test.cpp
Microsoft (R) C/C++ Optimizing Compiler Version 19.29.30136 for x64
Copyright (C) Microsoft Corporation. All rights reserved.
sfinae_test.cpp
..\sfinae_test.cpp(21): error C2535: 'enable_if<0,void>::type tester::operator ()(int *)': member function already defined or declared
..\sfinae_test.cpp(16): note: see declaration of 'tester::operator ()'
..\sfinae_test.cpp(44): error C2672: 'tester::operator ()': no matching overloaded function found
..\sfinae_test.cpp(44): error C2893: Failed to specialize function template 'enable_if<0,void>::type tester::operator ()(int *)'
..\sfinae_test.cpp(16): note: see declaration of 'tester::operator ()'
..\sfinae_test.cpp(44): note: With the following template arguments:
..\sfinae_test.cpp(44): note: 'T=float'
Folding all the code into if constexpr works.
Related issue: https://developercommunity.visualstudio.com/t/constexpr-function-in-sfinae/1048586
Is there any solution/hack to this problem?
You can use enable_if as template parameter, like this.

Template Parameter Pack Fails on Clang but not VS 2015

I'm working on a function which invokes a supplied function with a variable number of arguments. It compiles and works correctly on Visual Studio 2015, but fails to compile on Clang . I've prepared a demonstration which shows what I'm trying to do. The error I get in Clang is:
prog.cpp: In function 'int main()': prog.cpp:31:2: error: no matching
function for call to 'run(std::vector&, void ()(int&, const
int&), const int&)' ); ^ prog.cpp:7:6: note: candidate:
template void
run(std::vector&, const std::function&,
mutrArgs ...) void run(
^ prog.cpp:7:6: note: template argument deduction/substitution failed: prog.cpp:31:2: note: mismatched types 'const
std::function' and 'void ()(int&, const
int&)' );
#include <functional>
#include <iostream>
#include <vector>
using namespace std;
template<int RepeatTimes, class ... mutrArgs>
void run(
vector<int>& vec,
const function<void(int&, mutrArgs ...)>& mutr,
mutrArgs ... args
)
{
for (int times{0} ; times < RepeatTimes ; ++times)
for (auto& item : vec)
mutr(item, args...);
}
void adder(int& i, const int& val)
{
i += val;
}
int main()
{
vector<int> v{0,1,2,3,4,5,6,7,8,9};
const int addValue{4};
run<2, const int&>(
v,
&adder,
addValue
);
for (auto i : v)
cout << i << " ";
cout << endl;
return 0;
}
run<2, const int&> just state the first argument, but doesn't deactivate deduction.
run<2, const int&>(v, &adder, addValue);
has 2 places to deduce mutrArgs:
addValue -> mutrArgs = { const int& }
&adder which is not a std::function and so fail.
Taking address of function fix that problem
auto call_run = &run<2, const int&>;
call_run(v, &adder, addValue);
Strangely, clang doesn't support the inlined usage contrary to gcc :/
(&run<2, const int&>)(v, &adder, addValue);
If you want to disable deduction, you may make your template arg non deducible:
template <typename T> struct identity { using type = T; };
template <typename T> using non_deducible_t = typename identity<T>::type;
And then
template<int RepeatTimes, class ... mutrArgs>
void run(
std::vector<int>& vec,
const std::function<void(int&, non_deducible_t<mutrArgs> ...)>& mutr,
non_deducible_t<mutrArgs> ... args
)
Demo
Even if in your case a simple typename F as suggested by Joachim Pileborg seems better.
If you look at all standard library algorithm function, at least the ones taking a "predicate" (a callable object) they take that argument as a templated type.
If you do the same it will build:
template<int RepeatTimes, typename F, class ... mutrArgs>
void run(
vector<int>& vec,
F mutr,
mutrArgs ... args
)
{
...
}
See here for an example of you code. Note that you don't need to provide all template arguments, the compiler is able to deduce them.

Unresolved overloaded function type when attempting to pass a function as an argument

I receive the following error when attempting to compile a lone C++ testing file under G++ with C++11 in place.
spike/cur_spike.cpp: In function ‘int main()’:
spike/cur_spike.cpp:60:44: error: no matching function for call to ‘callFunctionFromName(<unresolved overloaded function type>, std::__cxx11::string&)’
callFunctionFromName (outputLine, param);
^
spike/cur_spike.cpp:49:7: note: candidate: template<class funcT, class ... Args> funcT callFunctionFromName(funcT (*)(Args ...), Args ...)
funcT callFunctionFromName (funcT func(Args...), Args... args) {
^
spike/cur_spike.cpp:49:7: note: template argument deduction/substitution failed:
spike/cur_spike.cpp:60:44: note: couldn't deduce template parameter ‘funcT’
callFunctionFromName (outputLine, param);
^
Here's the code.
#include <iostream>
#include <string>
template <typename T>
void outputLine (T text) {
std::cout << text << std::endl;
}
template <typename funcT>
funcT callFunctionFromName (funcT func()) {
return func ();
}
template <typename funcT, typename... Args>
funcT callFunctionFromName (funcT func(Args...), Args... args) {
return func (args...);
}
int main () {
std::string param = "Testing...";
callFunctionFromName (outputLine, param);
return 0;
}
I'm currently building this on a Linux system using G++, this code snippet contains all code related to this issue. I'm particularly intrigued about the fact that the compiler is unable to deduce the template parameter funcT for some reason, even though the outputLine function has a clear return type of void.
Setting a pointer of outputLine using void (*outputLinePtr)(std::string) = outputLine and using the pointer as the argument instead does nothing. Any help would be much appreciated.
You can manually set template argument.
callFunctionFromName (outputLine<std::string>, param);

Error in VS2013 when attempting to partially specialize a class template with another class template

Given the following class and function templates:
template <typename WrappedType, ParameterType ParamType, bool IsOutputParameter>
class WrappedParameter; // Definition left out for brevity
template <typename T>
struct ParameterUnwrapper
{
static T UnwrapParameter(const T& in_param)
{
return in_param;
}
};
template <typename T, ParameterType ParamType, bool IsOutputParameter>
struct ParameterUnwrapper<WrappedParameter<T, ParamType, IsOutputParameter>>
{
static T UnwrapParameter(const WrappedParameter<T, ParamType, IsOutputParameter>& in_param)
{
return in_param.GetWrapped();
}
};
template <typename T>
T UnwrapParameter(T in_param)
{
return Impl::ParameterUnwrapper<T>::UnwrapParameter(in_param);
}
template <typename T>
Impl::WrappedParameter<T, Impl::POINTER_PARAMETER, true> WrapOutputPointerParameter(T in_param)
{
return Impl::WrappedParameter<T, Impl::POINTER_PARAMETER, true>(in_param);
}
template <typename MemFunc, typename ...Args>
HRESULT ExecuteAndLog(
MemFunc in_memberFunction,
const std::string& in_methodName,
Args... args) //-> decltype((m_wrapped->*in_memberFunction)(UnwrapParameter(args)...))
{
return ExecuteFunctorAndLog(
[&]() { return (m_wrapped->*in_memberFunction)(UnwrapParameter(args)...); },
in_methodName,
args...);
}
The following call: (The ExecuteAndLog)
HRESULT STDMETHODCALLTYPE AccessorWrapper::AddRefAccessor(
HACCESSOR hAccessor,
DBREFCOUNT *pcRefCount)
{
return ExecuteAndLog(
&IAccessor::AddRefAccessor,
"AddRefAccessor",
hAccessor,
WrapOutputPointerParameter(pcRefCount));
}
Gives me errors:
error C2664: 'HRESULT (HACCESSOR,DBREFCOUNT *)' : cannot convert argument 2 from 'Impl::WrappedParameter<DBREFCOUNT *,POINTER_PARAMETER,true>' to 'DBREFCOUNT *'
No user-defined-conversion operator available that can perform this conversion, or the operator cannot be called
see reference to function template instantiation 'ExecuteAndLog<HRESULT(__stdcall IAccessor::* )(HACCESSOR,DBREFCOUNT *),HACCESSOR, Impl::WrappedParameter<DBREFCOUNT *,POINTER_PARAMETER,true>>(MemFunc,const std::string &,HACCESSOR,Impl::WrappedParameter<DBREFCOUNT *,POINTER_PARAMETER,true>)' being compiled
with
[
MemFunc=HRESULT (__stdcall IAccessor::* )(HACCESSOR,DBREFCOUNT *)
]
see reference to function template instantiation 'ExecuteAndLog<HRESULT(__stdcall IAccessor::* )(HACCESSOR,DBREFCOUNT *),HACCESSOR,Impl::WrappedParameter<DBREFCOUNT *,POINTER_PARAMETER,true>>(MemFunc,const std::string &,HACCESSOR,Impl::WrappedParameter<DBREFCOUNT *,POINTER_PARAMETER,true>)' being compiled
with
[
MemFunc=HRESULT (__stdcall IAccessor::* )(HACCESSOR,DBREFCOUNT *)
]
I think I've messed up the partial specialization of ParameterUnwrapper (or my approach is just wrong). Any advice?
More information:
Impl is a nested namespace (alongside the namespace all the provided templates except ExecuteAndLog are in)
m_wrapped is of type IAccessor* (the COM interface) in this case.
enum ParameterType
{
POINTER_PARAMETER,
ARRAY_PARAMETER
};
UPDATE:
Here's a self contained example: http://codepad.org/lwTzVImb
The error I get in VS2013 for this one is:
error C2664: 'int (int,int **,size_t *)' : cannot convert argument 2 from 'WrappedParameter<int **,ARRAY_PARAMETER,true>' to 'int **'
No user-defined-conversion operator available that can perform this conversion, or the operator cannot be called
see reference to function template instantiation 'int ExecuteAndLog<int(__thiscall A::* )(int,int **,size_t *),int,WrappedParameter<int **,ARRAY_PARAMETER,true>,size_t*>(MemFunc,const std::string &,int,WrappedParameter<int **,ARRAY_PARAMETER,true>,size_t *)' being compiled
with
[
MemFunc=int (__thiscall A::* )(int,int **,size_t *)
]
I figured it out!
The issue was the return type of UnwrapParameter. Once I changed the declaration of it to
template <typename T>
auto UnwrapParameter(T in_param) -> decltype(Impl::ParameterUnwrapper<T>::UnwrapParameter(in_param))
It compiled. Shame the compiler didn't complain about the definition of that function, rather than trusting its declared return value.
I have some other problems right now but at least I've made progress.