I'm trying to make my class be convertible to a function pointer, for a slew of reasons unrelated to this post.
When I try to do this with a non-template class, it works fine. Below, Bar bar; bar(1) correctly compiles, and segfaults as-expected. But Foo<int>; foo(1) doesn't compile at all.
I've tried multiple compilers, and I get: mismatched types 'Args' and 'int'
Any ideas? Live demo: https://wandbox.org/permlink/alSGBssfSd4pHgdl
#include <iostream>
#include <tuple>
using namespace std;
template<typename... Args>
using Test = void(*)(Args...);
template<typename T>
struct Foo {
template<typename... Args>
operator Test<Args...>() {
return Test<Args...>{};
}
};
struct Bar {
template<typename... Args>
operator Test<Args...>() {
return Test<Args...>{};
}
};
int main()
{
Foo<int> foo;
// foo(1);
Bar bar;
bar(1);
return 0;
}
Tried this awful syntax, too:
template<typename... Args>
(*operator void() const)(Args...) {
return {};
}
You can try this:
#include <iostream>
#include <tuple>
using namespace std;
template<typename... Args>
using Test = void(*)(Args...);
template<typename T>
struct Foo {
template<typename... Args>
operator Test<Args...>()
{
std::cout << __FUNCTION__ << std::endl;
return Test<Args...>{};
}
};
struct Bar {
template<typename... Args>
operator Test<Args...>()
{
std::cout << __FUNCTION__ << std::endl;
return Test<Args...>{};
}
};
int main()
{
Foo<int> foo;
auto x = static_cast<Test<int, double>>(foo);
Bar bar;
auto y = static_cast<Test<char, float>>(bar);
return 0;
}
When using Visual C++ 2019, I get the following run-time output:
Foo<int>::operator void (__cdecl *)(int,double)
Bar::operator void (__cdecl *)(char,float)
The use of the static_cast is to force the usage of the overloaded operator member functions.
Alternatively, you can also try:
#include <iostream>
#include <tuple>
#include <type_traits>
using namespace std;
template<typename... Args>
using Test = void(*)(Args...);
template<typename T>
struct Foo {
template<typename... Args>
Test<Args...> operator()(int x)
{
return Test<Args...>{};
}
};
struct Bar {
template<typename... Args>
Test<Args...> operator()(int x)
{
return Test<Args...>{};
}
};
int main()
{
Foo<int> foo;
auto w = foo.template operator()<int, double>(1);
std::cout << "w: " << typeid(w).name() << std::endl;
auto x = foo(2);
std::cout << "x: " << typeid(x).name() << std::endl;
Bar bar;
auto y = bar.template operator()<char, float>(3);
std::cout << "y: " << typeid(y).name() << std::endl;
auto z = bar(4);
std::cout << "z: " << typeid(z).name() << std::endl;
return 0;
}
When using Visual C++ 2019, I get the following run-time output:
w: void (__cdecl*)(int,double)
x: void (__cdecl*)(void)
y: void (__cdecl*)(char,float)
z: void (__cdecl*)(void)
In this way, the object is now callable and returns a function pointer.
Related
I have a problem with specialization of a member function of a generic struct.
My goal is to specialize the member function Run of Bar with all kinds of std::vector.
#include <iostream>
#include <vector>
// (1) compile
template <typename T>
struct Foo {
T Run() {
std::cout << "Foo not specialized" << std::endl;
return T();
};
};
// (2) compile
template <typename T>
struct Foo<std::vector<T>> {
std::vector<T> Run() {
std::cout << "Foo specialized" << std::endl;
return std::vector<T>();
};
};
template <typename T> struct Bar
{
T Run();
};
// (3) compiles
template<typename T>
T Bar<T>::Run() {
std::cout << "Bar not specialized" << std::endl;
return T();
};
// (3) compiles
template<>
std::vector<bool> Bar<std::vector<bool>>::Run() {
std::cout << "Bar specialized" << std::endl;
return std::vector<bool>();
};
// (4) wont compile: error: invalid use of incomplete type 'struct Bar<std::vector<T> >
template<typename T>
std::vector<T> Bar<std::vector<T>>::Run() {
std::cout << "Bar specialized" << std::endl;
return std::vector<T>();
};
int main(int argc, char const *argv[]) {
Foo<bool> f1;
bool rf1 = f1.Run();
Foo<std::vector<int>> f2;
std::vector<int> rf2 = f2.Run();
Bar<bool> b1;
bool rb1 = b1.Run();
Bar<std::vector<bool>> b2;
std::vector<bool> rb2 = b2.Run();
Bar<std::vector<int>> b3;
std::vector<int> rb3 = b3.Run();
return 0;
};
it would not compile see (4) if i comment it out it work probably.
Is there a way to get this working. Thank you in advance.
Demo not compiling
Demo compiling
Template functions cannot be a partially specialized.
You can do it with a trampoline and overloading. Like Run(){ DoRun(*this) then write DoRun overloads.
I'd like to create a functor from a class A that inherits from enable_shared_from_this, that is for a class like this:
class A: public std::enable_shared_from_this<A> {
...
}
I want to have a member function that looks something like this (incorrect code):
template <typename Args...>
std::function<void(Args ...)> functor_from_this(void (A::*method)(Args...)) {
return std::bind(method, shared_from_this());
}
The code above generates several errors, starting with warning C4180: qualifier applied to function type has no meaning; ignored, which makes me suspect I'm going about this the wrong way. How do I go about achieving something like this?
Extra credits for (a) binding the Args... to the functor as well so I get a function whose signature is void fn(), and (b) doing all this in a general-purpose class that inherits from enable_shared_from_this<T>.
Well, for C++14 the solution is easy enough to write. Just forgo std::bind and return a lambda instead:
#include <memory>
#include <iostream>
#include <functional>
struct A: std::enable_shared_from_this<A> {
template <typename... Args>
std::function<void(Args...)> functor_from_this(void (A::*method)(Args...)) {
return [=, obj = shared_from_this()](Args... args) {
((*obj).*method)(args...);
};
}
void foo(int) { std::cout << "foo" << '\n'; }
void bar() { std::cout << "bar" << '\n'; }
};
int main()
{
auto a = std::make_shared<A>();
auto f = a->functor_from_this(&A::foo);
auto b = a->functor_from_this(&A::bar);
f(1);
b();
}
For C++11 as Jarod42 pointed out in a comment, use a much simpler intermediate variable:
#include <memory>
#include <iostream>
#include <functional>
struct A: std::enable_shared_from_this<A> {
template <typename... Args>
std::function<void(Args...)> functor_from_this(void (A::*method)(Args...)) {
auto obj = shared_from_this();
return [=](Args... args) {
((*obj).*method)(args...);
};
}
void foo(int) { std::cout << "foo" << '\n'; }
void bar() { std::cout << "bar" << '\n'; }
};
int main()
{
auto a = std::make_shared<A>();
auto f = a->functor_from_this(&A::foo);
auto b = a->functor_from_this(&A::bar);
f(1);
b();
}
For extra credit (B), here is the solution I found, based on the answer by StoryTeller & Jarod:
#include <memory>
#include <iostream>
#include <functional>
template <class T>
class enable_functor_from_this: public std::enable_shared_from_this<T> {
public:
template <typename... Args>
decltype(auto) functor_from_this(void (T::*method)(Args...)) {
auto obj = this->shared_from_this();
return [=](Args... args) {
((*obj).*method)(args...);
};
}
};
struct A: enable_functor_from_this<A> {
void foo(int) { std::cout << "foo" << '\n'; }
void bar() { std::cout << "bar" << '\n'; }
};
int main()
{
auto a = std::make_shared<A>();
auto f = a->functor_from_this(&A::foo);
auto b = a->functor_from_this(&A::bar);
f(1);
b();
}
I'm trying to overload a function inside template struct using friend.
I want to use that to map a type to another type. Here in the code below I want to map the type int to MyType.
Here's what I did so far:
void map(...){} // Worst case
// Here's the class that will overload our function
template<typename Type, typename T>
struct MakeFunction {
friend Type map(T) { return {}; }
};
// Make the function with int?
struct MyType : MakeFunction<MyType, int> {};
int main() {
// The type obtained is void, worst case choosed. The expected result is `MyType` as return type.
std::cout << typeid(decltype(map(int{}))).name() << std::endl;
return 0;
}
Then, I tried that:
template<typename T>
void map(){} // Worst case
// Here's the class that will overload our function
template<typename Type, typename T>
struct MakeFunction {
// Compilation error.
friend Type map<T>() { return {}; }
};
struct MyType : MakeFunction<MyType, int> {};
int main() {
std::cout << typeid(decltype(map<int>())).name() << std::endl;
return 0;
}
But the compilation failed with :
error: defining explicit specialization ’map<T>’ in friend delcaration
How can I change the declaration so the right function is picked? Or is there a way to map types without a ton a boilerplate?
Below code shows how you can define a macro DEFINE_TYPE_MAPPING meeting your needs (this is to some extent a sketch demonstrating the idea):
#include <iostream>
#include <typeinfo>
void map(...){} // Worst case
template<class T> struct TypeMapping;
template<class T>
typename TypeMapping<T>::type map(const T&);
#define DEFINE_TYPE_MAPPING(T, U) \
template<> struct TypeMapping<T> { typedef U type; };
struct MyType {};
DEFINE_TYPE_MAPPING(int, MyType);
DEFINE_TYPE_MAPPING(char, float*);
DEFINE_TYPE_MAPPING(std::ostream, unsigned long);
int main() {
std::cout << typeid(decltype(map(int{}))).name() << std::endl;
std::cout << typeid(decltype(map('c'))).name() << std::endl;
std::cout << typeid(decltype(map(std::cout))).name() << std::endl;
std::cout << typeid(decltype(map(1.0))).name() << std::endl;
return 0;
}
How about:
namespace detail{
// To keep exact type
template <typename> struct tag {};
// The mapping
float map(tag<char>);
MyType map(tag<int>);
char map(tag<const int&>);
// ... and so on
}
template <typename T>
using map_t = decltype(detail::map(detail::tag<T>{}));
And then
int main() {
std::cout << typeid(map_t<int>).name() << std::endl;
std::cout << typeid(map_t<const int&>).name() << std::endl;
}
Essentially I want a template class with an array whose size is a template parameter, to hold constant content.
Something like:
template<size_t S> struct Foo {
const int bar[S];
Foo(const int(&par)[S]) : bar(par) {
cout << "bar size is " << S << endl;
}
};
auto foo = Foo({1,2,3});
I have been searching and tinkering a bit, and almost have a workaround implemented with an intermediate static method and using std::array:
template<size_t S> struct Baz {
const array<int,S> qux;
Baz(const array<int,S>&par) : qux(par) {
cout << "size is " << S << endl;
}
};
template<size_t S> Baz<S>
GetBaz(const array<int,S>&in) {
return Baz<S>(in);
}
int main() {
auto sample = GetBaz({1,2,3});
return 0;
}
... Which is already quite some boilerplate, but still the std::array does not seem to get constructed from an initialiser list? :-(
prog.cpp: In function 'int main()':
prog.cpp:27:30: error: no matching function for call to 'GetBaz(<brace-enclosed initializer list>)'
auto sample = GetBaz({1,2,3});
Post-DR1591 built-in array bound are now deducible from a braced-init-list, so:
template<size_t S> struct Baz {
const array<int,S> qux;
Baz(const array<int,S>&par) : qux(par) {
cout << "size is " << S << endl;
}
Baz(const int (&par)[S]) : qux(std::experimental::to_array(par)) {}
};
template<size_t S> Baz<S>
GetBaz(const int (&in)[S]) {
return Baz<S>(in);
}
std::experimental::to_array creates an std::array from a built-in one. See the linked cppreference page for implementation.
You can go built-in arrays all the way, but it's somewhat more annoying:
template<size_t S> struct Baz {
const int bar[S];
template<size_t... Is>
Baz(const int (&par)[S], std::index_sequence<Is...>)
: bar { par[Is]... } {}
Baz(const int (&par)[S]) : Baz(par, std::make_index_sequence<S>()) {}
};
template<size_t S> Baz<S>
GetBaz(const int (&in)[S]) {
return Baz<S>(in);
}
Not sure if I fully understood the questions. Is that what you are trying to achieve?
#include <iostream>
#include <array>
template<size_t S> struct Baz {
const std::array<int,S> qux;
Baz(const std::array<int,S>& par) : qux(par) {
std::cout << "size is " << qux.size() << std::endl;
}
};
int main() {
auto sample = Baz<5>({1,2,3}); // size = 5, values = 1, 2, 3, 0, 0
return 0;
}
Summary:
Use an std::array instead of a raw array.
Specify the template argument, eg: Baz<5>(...).
Class template arguments are not deduced.
You can do it with a classic C array, but using a variadic constructor
#include <array>
#include <cstddef>
#include <iostream>
using namespace std;
template <size_t S> struct Foo {
const int bar[S];
const std::array<int, S> bar2;
template <typename ... I>
Foo (const I & ... i) : bar {i...}, bar2 {{i...}}
{
cout << "bar size is " << S << " == " <<
(sizeof(bar)/sizeof(bar[0])) << " == " << bar2.size() << endl;
}
};
int main()
{
Foo<3> foo {1,2,3};
auto foo2 = Foo<4>{1,2,3,4};
return 0;
}
I want to use SFINAE to enable a particular template if the user passes a function pointer as a parameter.
I have googled around but found nothing - I also tried looking at the <type_traits> documentation but couldn't find anything that resembled a is_function_ptr<T>.
By function pointer, I mean global function pointers, like TReturn(*)(TArgs...).
Below is a type trait determining if something is a function pointer and a couple of test cases. Note, that to test if something is a function pointer, you need to test if std::is_pointer<P>::value is true and if std::is_function<T>::value is true where T is P with the pointer removed. The code below just does that:
#include <type_traits>
#include <iostream>
#include <utility>
template <typename Fun>
struct is_fun_ptr
: std::integral_constant<bool, std::is_pointer<Fun>::value
&& std::is_function<
typename std::remove_pointer<Fun>::type
>::value>
{
};
template <typename Fun>
typename std::enable_if<is_fun_ptr<Fun>::value>::type
test(Fun) {
std::cout << "is a function pointer\n";
}
template <typename Fun>
typename std::enable_if<!is_fun_ptr<Fun>::value>::type
test(Fun) {
std::cout << "is not a function pointer\n";
}
void f0() {}
void f1(int) {}
void f2(int, double) {}
struct s0 { void operator()() {} };
struct s1 { void operator()(int) {} };
struct s2 { void operator()(int, double) {} };
int main()
{
int v0(0);
int* p0(&v0);
void (*p1)() = &f0;
void (**p2)() = &p1;
std::cout << "v0="; test(v0);
std::cout << "p0="; test(p0);
std::cout << "p1="; test(p1);
std::cout << "p2="; test(p2);
std::cout << "f0="; test(&f0);
std::cout << "f1="; test(&f1);
std::cout << "f2="; test(&f2);
std::cout << "s0="; test(s0());
std::cout << "s1="; test(s1());
std::cout << "s2="; test(s2());
std::cout << "l0="; test([](){});
std::cout << "l1="; test([](int){});
std::cout << "l2="; test([](int, double){});
}
No SFINAE is needed to accept a function pointer or a member function pointer. To distinguish function objects from non-callable stuff SFINAE is needed, there's probably no way around this.
#include <utility>
#include <iostream>
template <typename Ret, typename... Parm>
void moo (Ret (*fp)(Parm...))
{
std::cout << "funptr" << std::endl;
}
template <typename Ret, typename Owner, typename... Parm>
void moo (Ret (Owner::*fp1)(Parm...))
{
std::cout << "memfunptr" << std::endl;
}
template <typename Funobj, typename... Parm,
typename Ret =
decltype((std::declval<Funobj>())
(std::forward(std::declval<Parm>())...))>
void moo (Funobj functor)
{
std::cout << "funobj" << std::endl;
}
void x1() {}
struct X2 { void x2() {} };
struct X3 { void operator()(){} };
int main()
{
moo(x1);
moo(&X2::x2);
moo(X3());
}