alias for multi parameter function template - templates

I am trying to create a template for a multi-parameter function, and then an alias for a particular instantiation. From this really good post:
C++11: How to alias a function?
I found example code that works for a single function parameter and single template parameter:
#include <iostream>
namespace Bar
{
void test()
{
std::cout << "Test\n";
}
template<typename T>
void test2(T const& a)
{
std::cout << "Test: " << a << std::endl;
}
}
void (&alias)() = Bar::test;
void (&a2)(int const&) = Bar::test2<int>;
int main()
{
Bar::test();
alias();
a2(3);
}
When I try to expand to two function parameters as such:
void noBarTest(T const& a, T const& b)
{
std::cout << "noBarTest: " << a << std::endl;
}
void(&hh)(int const&, int const&) = noBarTest<int, int>;
I get these errors in Visual Studio:
error C2440: 'initializing' : cannot convert from 'void (__cdecl
*)(const T &,const T &)' to 'void (__cdecl &)(const int &,const int &)'
IntelliSense: a reference of type "void (&)(const int &, const int &)"
(not const-qualified) cannot be initialized with a value of type
""
I thought I followed the pattern exactly in expanding to 2 arguments.
What's the proper syntax for this?

template <typename T>
void noBarTest(T const& a, T const& b)
{
}
void(&hh)(int const&, int const&) = noBarTest<int>; // Only once
int main() {
return 0;
}
The type parameter int needs to be specified only once in noBarTest<int>.

Related

How to static_cast a pointer to const member function?

Surprisingly (embarrassingly?) I cannot get the syntax of the static_const of a const member function right. In short (details below) if the member function is not marked const I use:
static_cast<std::vector<double> (mymodule::Foo::*)(const std::vector<double>&)>(&mymodule::Foo::bar)
but marking the member function Foo::bar(...) const the compiler does not know what to do:
error: address of overloaded function 'bar' cannot be static_cast to type 'std::vector<double> (mymodule::Foo::*)(const std::vector<double> &)'
Where should I put the function's constness?
Details
I'm trying to create Python binding for the following module:
namespace mymodule {
class Foo
{
public:
Foo() = default;
template <class T>
T bar(const T& a) const
{
T ret = a;
for (auto& i : ret) {
i *= 2.0;
}
return ret;
}
template <class T>
T bar(const T& a, double f) const
{
T ret = a;
for (auto& i : ret) {
i *= f;
}
return ret;
}
};
} // namespace mymodule
whereby I write the Python bindings with pybind11:
#include <pybind11/pybind11.h>
namespace py = pybind11;
PYBIND11_MODULE(example, m)
{
py::class_<mymodule::Foo>(m, "Foo")
.def(py::init<>())
.def("bar",
static_cast<std::vector<double> (mymodule::Foo::*)(const std::vector<double>&)>(&mymodule::Foo::bar),
py::arg("a"))
.def("bar",
static_cast<std::vector<double> (mymodule::Foo::*)(const std::vector<double>&, double)>(&mymodule::Foo::bar),
py::arg("a"),
py::arg("f"));
}
which fails to compile:
.../example.cpp:54:14: error: address of overloaded function 'bar' cannot be static_cast to type 'std::vector<double> (mymodule::Foo::*)(const std::vector<double> &)'
static_cast<std::vector<double> (mymodule::Foo::*)(const std::vector<double>&)>(&mymodule::Foo::bar),
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.../example.cpp:19:7: note: candidate function template
T bar(const T& a) const
^
.../example.cpp:29:7: note: candidate function template
T bar(const T& a, double f) const
^
.../example.cpp:58:14: error: address of overloaded function 'bar' cannot be static_cast to type 'std::vector<double> (mymodule::Foo::*)(const std::vector<double> &, double)'
static_cast<std::vector<double> (mymodule::Foo::*)(const std::vector<double>&, double)>(&mymodule::Foo::bar),
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.../example.cpp:19:7: note: candidate function template
T bar(const T& a) const
^
.../example.cpp:29:7: note: candidate function template
T bar(const T& a, double f) const
^
2 errors generated.
You should add const at last as:
static_cast<std::vector<double> (mymodule::Foo::*)(const std::vector<double>&) const>(&mymodule::Foo::bar),
// ^^^^^

Force template deduction from a function to produce const references where applicable

running through the following function using gdb in vscode tells me that the deduced argTypes for a function of the form T (*)(const int &, const int *, int &, int) are int const int * int & and int respectively. Is there any way to force the compiler to deduce const Type & when presented with a const Type & argument? Or is there some other means by which I can extract that type information in a useful way?
#include<typeinfo>
template<typename T, typename...argTypes>
void testfunc(T (*f)(argTypes...))
{
const char *a[] = { typeid(argTypes).name()... };
for(auto &av :a)
{
std::cout << av << std::endl;
}
}
edit:
A little more context: this function obviously does little to nothing, but the problem function that spawned it also takes in all the arguments to be run with f in a way that they are not deduced, but converted.
This presents a problem for non-copyable objects to be used as const references.
An example of using testfunc is as follows:
#include "testfunc.h"
std::vector<bool> funcToTest(const int &a, const int *b, int &c, int d)
{
std::vector<bool> out;
out.push_back(&a == b);
out.push_back(&c == b);
out.push_back(&d == b);
return out;
}
int main()
{
// put a breakpoint here, and step in, you would see that 'a'
// describes the situation as described above.
testfunc(funcToTest);
}
The issue here is with typeid, not template deduction. If you use
template<typename... Ts>
struct types;
template<typename T, typename...argTypes>
void testfunc(T (*f)(argTypes...))
{
types<argTypes...>{};
}
You get an nice error message like
main.cpp: In instantiation of 'void testfunc(T (*)(argTypes ...)) [with T = std::vector<bool>; argTypes = {const int&, const int*, int&, int}]':
main.cpp:30:24: required from here
main.cpp:12:5: error: invalid use of incomplete type 'struct types<const int&, const int*, int&, int>'
12 | types<argTypes...>{};
| ^~~~~
main.cpp:7:8: note: declaration of 'struct types<const int&, const int*, int&, int>'
7 | struct types;
| ^~~~~
which shows you that the function parameter types are correctly deduced.
With typeid if the type is a reference, then it returns the referred to type. It also drops all cv-qualifactions on the types. That means
int main()
{
std::cout << typeid(int).name() << "\n";
std::cout << typeid(int&).name() << "\n";
std::cout << typeid(const int).name() << "\n";
std::cout << typeid(const int&).name() << "\n";
std::cout << typeid(volatile int).name() << "\n";
std::cout << typeid(volatile int&).name() << "\n";
std::cout << typeid(const volatile int).name() << "\n";
std::cout << typeid(const volatile int&).name() << "\n";
}
prints
i
i
i
i
i
i
i
i

cannot convert argument 1 from 'int' to 'int &'

I'm getting the next error and I cannot find the reason for it:
Error C2664 'void SumID<long>::operator ()<int>(G &)': cannot convert argument 1 from 'int' to 'int &'
Why is passing an int by reference problematic?
I have the next class:
template <class T>
class SumID {
private:
T sumid;
public:
SumID():sumid()
{
}
SumID(T s)
{
sumid = s;
}
T getSumID()
{
cout << "inside getSum";
return sumid;
}
template <class G>
void operator() (G& a)
{
sumid = sumid+ a;
}
};
my main :
SumID<long> s;
for (int i = 0; i < 5; i++)
s(5); // <-- error here
When use s(5); the argument, 5, is not an lvalue. Hence, it cannot be used when the argument type is G&.
You can resolve the problem using one or both of the following approaches.
Create a variable and use it in the call.
int x = 5;
s(x);
Change the argument type to just G, G&& or G const&.
template <class G>
void operator() (G a) // Or (G&& a) or (G const& a)
{
sumid = sumid+ a;
}

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.

Template specialization works with g++ but not with Visual C++

I have a bunch of templated code that compiles fine under g++, but now when I try to build under windows with Visual C++ 2010 I get a bunch of errors.
I have a collection of template functions for getting and setting values in C++ objects from Lua code. For example, I have this template:
// Class Return type Getter function
template <typename T, typename U, U (T::*Getter)() const>
int luaU_get(lua_State* L)
{
T* obj = luaW_check<T>(L, 1); // Gets userdata from stack and checks if it's of type T
luaU_push(L, (obj->*Getter)()); // Runs the getter function specified in the template, and pushes the
return 1;
}
(The complete file can be found here)
Which is instantiated here:
static luaL_reg TextArea_MT[] =
{
// Class Return type Getter function
{ "GetCharacterSize", luaU_get<TextArea, unsigned int, &TextArea::GetCharacterSize> },
{ NULL, NULL }
};
The signature for that getter is as follows:
unsigned int GetCharacterSize() const;
I'm getting a bunch of errors like this:
2>C:\Users\Alex\Documents\Visual Studio 2010\Projects\game\dev\src\game\lua\LuaTextArea.cpp(103): error C2440: 'specialization' : cannot convert from 'unsigned int (__thiscall ag::ui::TextArea::* )(void) const' to 'unsigned int *(__thiscall ag::ui::TextArea::* const )(void) const'
2> Types pointed to are unrelated; conversion requires reinterpret_cast, C-style cast or function-style cast
2>C:\Users\Alex\Documents\Visual Studio 2010\Projects\game\dev\src\game\lua\LuaTextArea.cpp(103): error C2973: 'luaU_get' : invalid template argument 'unsigned int (__thiscall ag::ui::TextArea::* )(void) const'
2> C:\Users\Alex\Documents\Visual Studio 2010\Projects\game\dev\src\extern\LuaWrapper\LuaWrapperUtil.hpp(147) : see declaration of 'luaU_get'
2>C:\Users\Alex\Documents\Visual Studio 2010\Projects\game\dev\src\game\lua\LuaTextArea.cpp(103): error C2440: 'specialization' : cannot convert from 'unsigned int (__thiscall ag::ui::TextArea::* )(void) const' to 'unsigned int *ag::ui::TextArea::* const '
2> There is no context in which this conversion is possible
2>C:\Users\Alex\Documents\Visual Studio 2010\Projects\game\dev\src\game\lua\LuaTextArea.cpp(103): error C2973: 'luaU_get' : invalid template argument 'unsigned int (__thiscall ag::ui::TextArea::* )(void) const'
2> C:\Users\Alex\Documents\Visual Studio 2010\Projects\game\dev\src\extern\LuaWrapper\LuaWrapperUtil.hpp(131) : see declaration of 'luaU_get'
2>C:\Users\Alex\Documents\Visual Studio 2010\Projects\game\dev\src\game\lua\LuaTextArea.cpp(103): error C2440: 'specialization' : cannot convert from 'unsigned int (__thiscall ag::ui::TextArea::* )(void) const' to 'unsigned int ag::ui::TextArea::* const '
2> There is no context in which this conversion is possible
2>C:\Users\Alex\Documents\Visual Studio 2010\Projects\game\dev\src\game\lua\LuaTextArea.cpp(103): error C2973: 'luaU_get' : invalid template argument 'unsigned int (__thiscall ag::ui::TextArea::* )(void) const'
2> C:\Users\Alex\Documents\Visual Studio 2010\Projects\game\dev\src\extern\LuaWrapper\LuaWrapperUtil.hpp(123) : see declaration of 'luaU_get'
2>C:\Users\Alex\Documents\Visual Studio 2010\Projects\game\dev\src\game\lua\LuaTextArea.cpp(103): error C2440: 'initializing' : cannot convert from 'overloaded-function' to 'lua_CFunction'
2> None of the functions with this name in scope match the target type
This is a compiler bug in VC++. The following code is valid:
#include <iostream>
struct TextArea
{
unsigned GetCharacterSize() const { return 0; }
};
template<typename T, typename U, U (T::*)() const>
int foo()
{
return 1;
}
template<typename T, typename U, U* (T::*)() const>
int foo()
{
return 2;
}
int main()
{
std::cout << foo<TextArea, unsigned, &TextArea::GetCharacterSize>() << '\n';
}
And compiles with GCC 4.3.4, GCC 4.5.1, and Comeau 4.3.10.1 Beta2 (no link), but yields the following error with VC++ 2010 SP1:
error C2668: 'foo' : ambiguous call to overloaded function
EDIT: As for a workaround, it's ugly, but the only thing I can think of offhand is to use an extra layer of indirection so that there is no overloading involved:
#include <iostream>
struct WithPointer
{
unsigned* GetCharacterSize() const { return nullptr; }
};
struct WithoutPointer
{
unsigned GetCharacterSize() const { return 0u; }
};
template<bool UsePointerImplB>
struct kludge
{
template<typename T, typename U, U (T::*Getter)() const>
static int foo() { return 1; }
};
template<>
struct kludge<true>
{
template<typename T, typename U, U* (T::*Getter)() const>
static int foo() { return 2; }
};
int main()
{
std::cout
<< kludge<false>::foo<WithoutPointer, unsigned, &WithoutPointer::GetCharacterSize>() << '\n'
<< kludge<true>::foo<WithPointer, unsigned, &WithPointer::GetCharacterSize>() << '\n';
}
Effectively this is no different than just giving each overload a different name...
If you can force user to pick the actual return type of the function, the following works. Maybe, it'll be useful to you:
#include <iostream>
struct FooBar
{
int Foo( void ) const
{
std::cout << "FooBar::Foo()" << std::endl;
return ( 0 );
}
int * Bar( void ) const
{
std::cout << "FooBar::Bar()" << std::endl;
return ( 0 );
}
};
template< typename P00, typename P01, P01(P00::*p02)( void ) const >
void Call()
{
P00 lT;
( lT.*p02 )();
}
int main( void )
{
Call< FooBar, int, &FooBar::Foo > ();
Call< FooBar, int*, &FooBar::Bar > ();
return( 0 );
}
Program output:
FooBar::Foo()
FooBar::Bar()