I want to typedef a function pointer that points to a template function.
class A
{
template <typename T>
typedef void (*FPTR)<T>();
}
I have tried in this way and didn't succeed. Any idea about this thing?
As #HolyBlackCat pointed out, the normal function pointer should work as you have a simple templated void function, whose template parameter does not act on both return and argument types.
template <typename T>
void someVoidFunction() {}
using fPtrType = void(*)();
int main()
{
fPtrType funPtr1 = &someVoidFunction<int>;
fPtrType funPtr2 = &someVoidFunction<float>;
fPtrType funPtr3 = &someVoidFunction<std::string>;
return 0;
}
If it was the case, that template parameters depends on the function arg and return types you should have instantiated the function pointer as well for each kind.
template <typename T, typename U>
T someFunction(U u) {}
template <typename T, typename U>
using fPtrType = T(*)(U);
int main()
{
fPtrType<int, float> funPtr1 = &someFunction<int, float>; // instance 1
fPtrType<float, float> funPtr2 = &someFunction<float, float>; // instance 2
return 0;
}
Template functions produce functions. Template classes produce classes. Template variables produce variables.
Pointers can point at functions or variables. They cannot point at templates; templates have no address.
Typedef defines the type of a variable.
A template variable pointer could collectively point at various instances of a template function, but the initial binding would be done at compile time, and could only be aimed somewhere else one variable at a time.
Related
Is there a way to determine a return type of a member function pointer?
Code sample:
///// my library
void my_func(auto mptr) { // have to use `auto`
// some logic based on a return type of mptr: int, string, A, etc.
}
///// client code
struct A {
int foo();
std::string bar(int);
};
class B{
public:
A func(int, double);
};
// ... and many other classes
my_func(&A::foo);
my_func(&A::bar);
my_func(&B::func);
// ... many other calls of my_func()
I need to "fill in" my_func().
Edit:
I can't use std::result_of/std::invoke_result as I don't know the full list of parameters of mptr. It's not important with which params a method is supposed to be called as I'm not calling it. I would like to avoid creating an object of base class of mptr even if I'm able to determine it (using declval is ok).
You can use partial template specialization to determine the return type of mptr:
template <typename T>
struct ReturnType;
template <typename Object, typename Return, typename... Args>
struct ReturnType<Return (Object::*)(Args...)>
{
using Type = Return;
};
void my_func(auto mptr) {
typename ReturnType<decltype(mptr)>::Type obj;
}
Live Demo
You can write a function that deduces the type of a member function pointer, and returns the deduced return type. Note that only a declaration, and no definition is needed
template <typename C, typename Ret, typename... Args>
auto ret_type(Ret (C::*)(Args...)) -> Ret;
void my_func(auto mptr)
{
using type = decltype(ret_type(mptr));
}
In my opinion, this is also easier to read than the specialization solution.
Here's a demo
You can also account for cv-qualifiers by adding overloads. e.g.
template <typename C, typename Ret, typename... Args>
auto ret_type(Ret (C::*)(Args...) const) -> Ret;
Here's a demo
I want to write a concept that checks if the type has a static method called foo. That method will have a templated parameter (the function will be called multiple times later with different parameter types).
Because of that templated parameter, it's quite difficult to check it. For the start, I thought I only check if there is a member at all with that name.
The following code compiles with Clang, but doesn't compile with GCC, because it cannot resolve the address of the overloaded function T::foo.
template <typename T>
concept HasFoo = requires { T::foo; };
class Bar {
public:
template <typename T>
static void foo(T t);
};
static_assert(HasFoo<Bar>);
How do you correctly check for the existence of a templated static method (working in Clang and GCC)?
And ideally, can you even check more than this? Like checking if the return type is void, or if it is callable.
One way would be to include the templated type into the concept, but as I want to use the method with multiple different types.
So checking with only one type, like in the following code, is not enough.
template <typename T, typename T2>
concept HasFoo = requires { T::template foo<T2>; };
static_assert(HasFoo<Bar, int>);
How do you correctly check for the existence of a templated static method (working in Clang and GCC)? And ideally, can you even check more than this? Like checking if the return type is void, or if it is callable.
I do have some constraints on template arguments, for the sake of the simplified example in the question we can just assume it's an integer type.
To check if the class support a static template method foo() that is callable with an integer and return void, you can simply check
template <typename T>
concept HasFoo = std::is_same_v<decltype(T::foo(0)), void>;
If you also want to be sure that the foo() method is a template one, I suppose you can also check that converting &T::foo to different function pointer types you get different values, so (for example)
( (void*)(&T::template foo<int>)
!= (void*)(&T::template foo<long>))
Combining the two requirements,
template <typename T>
concept HasFoo = ( (void*)(&T::template foo<int>)
!= (void*)(&T::template foo<long>))
&& std::is_same_v<decltype(T::foo(0)), void>;
With
struct Bar1
{ template <typename T> static void foo (T) {} };
struct Bar2
{ static void foo (int) {} };
struct Bar3
{ template <typename T> static T foo; };
template <typename T>
T Bar3::foo;
struct Bar4
{ template <typename T> static int foo (T) { return 0; } };
you have
static_assert(HasFoo<Bar1>);
static_assert(not HasFoo<Bar2>); // not because foo() isn't template
static_assert(not HasFoo<Bar3>); // not because foo isn't callable
static_assert(not HasFoo<Bar4>); // not becasue foo() return int
I want to declare a function, which will take as a parameter a variable (let's say, int), which should be parametrized by a class. Speaking in terms of lambda calculus, I want my parameter to have a kind * -> int.
Example of a function I want to be able to write (Spec is the variable):
template <??? Specification, typename T>
auto make_array() {
return std::array<T, Specification<T>>;
}
Since C++14 we have variable templates, so we can do something like this:
template <typename T>
constexpr int digits = std::numeric_limits<T>::digits;
The problem is, how do I pass that into a function? In the notes section of cppreference it is stated that
Variable templates cannot be used as template template arguments.
But does that mean that there is actually no way to pass parametrized variable as a function parameter? What you can do is, for example, create a class which has a static field denoting value, but an obvious drawback is that the users of my function must derive from that class.
I believe there might be some workaround using SFINAE, but I lack skills in that area.
Unless you insist on using a variable template, you can use a type trait:
template <typename T> struct Specification;
you can specialize it for example for int:
template <>
struct Specification<int> {
static constexpr size_t value = 42;
};
and as you want to have different Specifications, pass it as template template parameter:
template <template<class> class S, typename T>
auto make_array() {
return std::array<T, S<T>::value>{};
}
Complete example:
#include <array>
#include <cstddef>
template <template<class> class S, typename T>
auto make_array() {
return std::array<T, S<T>::value>{};
}
template <typename T> struct Specification;
template <>
struct Specification<int> {
static constexpr size_t value = 42;
};
int main(){
auto x = make_array<Specification,int>();
}
Note that I was rather verbose for the sake of clarity. You can save a bit of typing by using std::integral_constant, eg:
template <>
struct Specification<double> : std::integral_constant<size_t,3> {};
As an follow-up on idclev's answer, you can avoid the need to explicitly specialise for the different types for individual "specifications" just by inheriting from e.g. integral_constant. For example, your desired usage was something like
template <template <typename T> int Specification, typename T>
auto make_array() {
return std::array<T, Specification<T>>;
}
template <typename T>
constexpr int digits = std::numeric_limits<T>::digits;
// ...
auto foo = make_array<digits, double>();
However, as you have noted, this is impossible: you cannot pass variable templates as template-template parameters. However, by turning digits into a structure directly you can do this:
template <template <typename T> class Specification, typename T>
auto make_array() {
// we no longer have the guarantee of the type here, unfortunately
// but you can use a static_assert to improve error messages
// (also using `std::size_t` here for correctness)
static_assert(
std::is_convertible<decltype(Specification<T>::value), std::size_t>::value,
"value must be convertible to size_t");
return std::array<T, Specification<T>::value>;
}
// use a type rather than a variable template
// we just inherit from integral constant to save on some typing
// (though you could do this explicitly as well)
template <typename T>
struct digits : std::integral_constant<int, std::numeric_limits<T>::digits> {};
// ...
// same call!
auto foo = make_array<digits, double>();
With same template declaration, is it possible to differ two functions with same name, same param list, but different return type?
template <class T>
int f()...
template <class T>
short f()...
Or, need some special code to achieve this?
Thanks.
You can indeed have function templates with same name, same parameter types, and same return type (but you cannot for regular functions).
template <class T>
int f() {/*..*/}
template <class T>
short f() {/*..*/}
But then their usage is not really easy/fine:
auto i = static_cast<int(*)()>(&f<float>)(); // Call int f<float>
auto s = static_cast<short(*)()>(&f<float>)(); // Call short f<float>
For example
template<class T, class U>
void f();
template<class T> using g = f<T, int>;
Or any similar idea for functions?
No. You cannot do that. You need to create a new function that calls f, forwarding all arguments and template arguments.
template<class T, class U>
void f();
template<class T>
void g() {
f<T, int>();
}
A C++14 alternative is a variable template of function pointer type:
template<typename T>
void (*g)() = &f<T, int>;
Although this approach ignores default arguments and probably has other quirks as well. I highly recommend the more verbose wrapping approach.
No, you can not do that as templated aliases are used to create aliases of types, not concrete data.
What you are trying to do is to create an alias/type from the address of a function as f<T, int> decays into a pointer to function.
You can however create a templated alias from the type of the function f.
template <typename T>
using g = typename std::add_pointer<decltype(f<T, int>)>::type;
int main() {
// Type of 'func' is 'void (*)()' with template arguments '{T1=double, T2=int}'.
g<double> func;
func = f<double, int>; // Point to function with same signature and template args.
func(); // Ok to call function.
}