I am working on a compile-time wrapper library and stumbled upon a problem of extracting a template parameter type from a given type.
The situation is the following. I have an unchangeable class R:
template <class T>
class R {};
I also have an unchangeable main function:
int main()
{
auto r = new R<int>();
// Function that knows the type of 'r'
create_obj<decltype(r)>();
delete r;
return 0;
}
The create_obj function is the one that I am working on. For visualization purposes, I will write it the following way:
template< class C >
void create_obj()
{
// Print the type of the function (Output: R<int>*)
std::cout << boost::typeindex::type_id<C>().pretty_name() << std::endl;
}
And the problem is that I need to access the int template parameter type of the R class from the create_obj function.
Pseudocode:
template<
template < class T >
class C<T>
>
void create_obj()
{
// Print the type of the function (Output: int)
std::cout << boost::typeindex::type_id<T>().pretty_name() << std::endl;
}
Is it possible to do it? I was going through the C++ documentation but I was not able to find any way to "detach" the template parameter type from the class definition.
Yes, it is possible, one way to do it:
template<typename T>
class R{};
template<typename C>
struct extract_impl{};
template<typename T>
struct extract_impl<R<T>>{
using type = T;
};
template<typename C>
using extracted_type = typename extract_impl<std::remove_pointer_t<std::decay_t<C>>>::type;
template< class C >
void create_obj()
{
static_assert(std::is_same_v<extracted_type<C>,int>);
}
int main()
{
create_obj<R<int>>();
}
The convention is that R would itself expose the type via using, but you wrote that it is unchangeable.
I instead calling create_obj() through the type of r
create_obj<decltype(r)>();
you can call it passing directly r, the solution is simple
template <typename T>
void create_obj (R<T> const *)
{ /* do something with T */ }
But if you want call create_obj() passing only the type R<T> (or a type pointer to R<T>) without instantiating an object of type R<T>, you can define a lightweight type wrapper
template <typename>
struct typeWrapper
{ /* empty! */ };
redefine create_obj() receiving a typeWrapper of a R<T> pointer
template <typename T>
void create_obj (typeWrapper<R<T> *> const &)
{ /* do something with T */ }
and call it using decltype(r)
create_obj(typeWrapper<decltype(r)>{});
or directly R<int> *
create_obj(typeWrapper<R<int> *>{});
Another alternative is declare create_obj as a struct/class
template <typename>
struct create_obj;
and define only a specialization based on a R<T> * pointer, with a static func() method in it
template <typename T>
struct create_obj<R<T> *>
{
static void func ()
{ /* do something with T */ }
};
You can use it through decltype(r)
create_obj<decltype(r)>::func();
or through R<int> *
create_obj<R<int> *>::func();
If you prefer, instead of a static func() method, you can insert in create_obj() an ordinary (non static) method; maybe an operator(). But, this way, you have to instantiate a create_obj object to call the method.
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 strip a class from a method type so that I have a function type left to work with.
stripClass has faked behavior that shows how I what I want as a result from the call stripClass(decltype(&A::B)).
The other lines show my general understanding.
#include <functional>
#include <iostream>
#define stripClass(type) void() //fake implementation of what I want to happen
struct A
{
void B() {}
};
int main()
{
decltype(&A::B) declTypeB = &A::B; //decltype of method
void (A::* decl)() = &A::B; //explicit type of method
void(*f)(); //function pointer thype when class type would be stripped from it
std::function<void()> fromFunction = f;
std::function<stripClass(decltype(&A::B))> fromDecltype = f;
return int{ 0 };
}
How can I strip the class from a method to get a function pointer while preserving the return type and the parameters.
You can write a type trait, can be also specialized to process argument / result types or deal with qualified methods differently:
template<typename x_PointerToMethod> class
t_SignatureExtractor;
template<typename x_Class, typename x_Returned, typename... x_Args> class
t_SignatureExtractor<x_Returned ( x_Class::* )(x_Args...)> final
{
public: using
t_ExtractedSignature = x_Returned (x_Args...);
};
template<auto x_p_method> using
t_ExtractedSignature = typename t_SignatureExtractor<decltype(x_p_method)>::t_ExtractedSignature;
...
t_ExtractedSignature<&A::B> * f{};
Implementing the trait for any member pointer, as it'd work just the same whether they're functions or objects:
template <class MemberPointer>
struct as_free_pointer;
template <class C, class T>
struct as_free_pointer<T C::*> {
using type = T *;
};
template <class MemberPointer>
using as_free_pointer_t = typename as_free_pointer<MemberPointer>::type;
I have been trying to create this class which can either use the default functor as an argument or the user can provide one if he wants. But I am unable to pass function pointer as my template argument. Can you please help me in understanding what I am missing.
template <typename T>
struct CheckFunctor
{
bool operator()(T obj)
{
return true;
}
};
template <typename _Ty,
class _Pr = CheckFunctor<_Ty>
>
class MyClass
{
typedef _Ty mapped_type;
typedef _Pr CanBeCleaned_type;
_Ty data;
CanBeCleaned_type predicate;
public:
void SomeMethod()
{
if( predicate(data))
{
std::cout << "Do something";
}
}
MyClass(_Ty timeOutDuration, _Pr pred = _Pr())
: data( timeOutDuration), predicate( pred)
{}
};
template< typename T>
struct CheckEvenFunctor
{
bool operator()(T val)
{
return (val%2 == 0);
}
};
bool CheckEven( int val)
{
return (val%2 == 0);
}
int main()
{
//Usage -1
MyClass<int> obj1( 5);
//Usage- 2
MyClass< int, CheckEven> obj2(6, CheckEven); //Error: 'CheckEven' is not a valid template type argument for parameter '_Pr'
//Usage -3
MyClass<int, CheckEvenFunctor<int>>( 7);
}
You are trying to pass CheckEven as a type parameter even though CheckEven is not a type but a function (of type bool(int)). You should define the type as a pointer to the type of function that you are passing. decltype is handy here:
MyClass< int, decltype(&CheckEven)> obj2(6, CheckEven);
You can also create a factory function and let the compiler deduce the template parameters:
template<class T, class F>
MyClass<T, F> makeClass(T timeOutDuration, F pred) {
return {timeOutDuration, pred};
}
auto obj2 = makeClass(6, CheckEven);
It is possible to allow a template parameter to be a function, but your MyClass is expecting the second argument to be a type, not a function. You might think that template specialization could be used to allow you to define MyClass to also take a function in the second template argument, but it won't work. Template specialization allows you to modify the behavior of MyClass for particular types that are passed as template arguments, but those types must still match the template definition of MyClass, which is that the two arguments are types.
You could modify the type of MyClass you are instantiating by making the second argument a function pointer type as suggested in a different answer, but you would lose the advantage of template expansion making your calls to functions inline. Another solution would be to create a helper class that will convert your function into a functor, and use that to create your MyClass instance.
template <bool P (int)>
struct F {
bool operator()(int obj) { return P(obj); }
};
//...
MyClass<int, F<CheckEven> > obj2(6);
I have tried to implement a "template template template" - template class to fullfill my needs ( I am quite new in using template metaprogramming). Unfortunately, I have found the following topic too late:
Template Template Parameters
Nevertheless, I need to implement something like listed below.
According to the compiler the last typedef is not working. I am not sure, but I think this is due to the limitation of 3x template restriction. Is there any possibility to bypass a 3xtemplate definition in this simple example?
template < typename TValueType >
class ITTranslator
{
public:
ITTranslator() = 0;
virtual ~ITTranslator() = 0;
virtual void doSomething() = 0;
}
template < typename TValueType >
class TConcreteTranslator1 : public ITTranslator<TValueType>
{
public:
TConcreteTranslator1(){}
~TConcreteTranslator1(){}
void doSomething() {}
}
template < typename TValueType >
class TConcreteTranslator2 : public ITTranslator<TValueType>
{
public:
TConcreteTranslator2(){}
~TConcreteTranslator2(){}
void doSomething() {}
}
template <
typename TValueType,
template < typename TValueType > class TTranslatorValueType
>
class ITClassifier
{
public:
ITClassifier() = 0;
virtual ~ITClassifier() = 0;
}
template <
typename TValueType,
template < typename TValueType > class TTranslatorValueType
>
class TConcreteClassifier1 : public ITClassifier<TValueType,TTranslatorValueType >
{
public:
TConcreteClassifier1() {}
~TConcreteClassifier1() {}
void dodo(){}
}
template <
typename TValueType,
template <typename TValueType> class TTranslatorValueType,
template <template<typename TValueType> class TTranslatorValueType> class TClassifierValueType
>
class ITAlgorithm
{
public:
ITAlgorithm()=0;
virtual ~TAlgorithm()=0;
virtual run() = 0;
}
template <
typename TValueType,
template <typename TValueType> class TTranslatorValueType,
template <template<typename TValueType> class TTranslatorValueType> class TClassifierValueType
>
class TConcreteAlgorithm1 : public ITAlgorithm<TValueType,TTranslatorValueType,TTranslatorValueType>
{
public:
TConcreteAlgorithm1 (){}
~TConcreteAlgorithm1 (){}
run()
{
TClassifierValueType< TTranslatorValueType>* l_classifier_pt = new TClassifierValueType< TTranslatorValueType>( );
// add this object to a internal list...
}
}
int main()
{
typedef TConcreteTranslator1< cvbase::uint32_t > translator_t;
typedef TConcreteClassifier1< cvbase::uint32_t, TConcreteTranslator1> classifier_t;
typedef TConcreteAlgorithm1 < cvbase::uint32_t, TConcreteTranslator1, TConcreteClassifier1> algorithm_t; // not possible
return 0;
}
Thanks a lot, I really appreciate any help!
EDIT:
I have extended my listing (I am pretty sure it will not compile :)) to show the motivation why I am using my weird concept :)
There is really no need to pass template template parameter around
here. Usually you can just take a normal template argument and provide
a reasonable default:
template<typename ValueType>
struct translator {};
template<typename ValueType, typename Translator = translator<ValueType>>
struct Classifier {};
template<typename ValueType,
typename Translator = translator<ValueType>,
typename Classifier = classifier<ValueType, Translator>
>
struct Algorithm {};
This is done the same way for allocator aware containers.
And please do away with the horrible hungarian-notation prefixes.
NB: It seems from your usage of constructors and destructors that you
don't really have a grasp of basic C++. You might want to stay away
from templates before you have understood easier concepts.
Yes it is possible to avoid template template parameters (of any level).
A template is basically a type-level function. You feed it a type, and get another type back.
A template template parameter is itself a type-level function, and a template that accepts such parameter is a higher-order type-level function.
It is possible to implement higher-order type-level functions with member templates, without ever using template template parameters. I'm not really sure you need it for your design, but here's a quick and dirty example:
// regular type, a.k.a. zeroth-order type-level function,
// a.k.a. "type of kind *"
struct N
{
int a;
};
// a first-order type-level function, a.k.a. "type of kind *->*"
// it is wrapped in a regular type
struct B
{
template <class A> struct Impl
{
void foo(A a)
{
int aa = a.a;
}
};
};
// a second-order type-level function
// that accepts a (wrapped) first-order type function
// and also a regular type. the kind of it would be (*->*)->*->*
// it applies its first argument to its second argument
struct Z
{
template <class X, class Y> struct Impl
{
typename X::template Impl<Y> ya;
void bar()
{
ya.foo(Y());
}
};
};
// now this is something: a third-order type-level function
// that accepts a (wrapped) second-order type-level function
// and a (wrapped) first-order type-level function
// and a zeroth-order type-level function
// it applies its first argument to its second and third arguments
// it is also wrapped in a regular type for consistency
// try to figure out its kind
struct T
{
template <class P, class Q, class R> struct Impl
{
typename P::template Impl<Q, R> yb;
void baz()
{
yb.bar();
}
};
};
T::Impl<Z, B, N> tt;
In this case you don't really need to have template parameters, basically the only variable type is TValueType right?
The other types can be resolved on the class body using TValueType.
Something like this:
template <
typename TValueType
>
class TAlgorithm
{
public:
// TTranslator <TValueType> whatever
// TTranslatorValueType <TValueType> whatever
TAlgorithm(){}
~TAlgorithm(){}
}
In templates as shown below, I would like the call Run(&Base::foo) succeed without the need to name the Base type twice (as is done in the compiling Run<Base>(&Base::foo) call). Can I have that? Possibly without adding a ton of Boost headers?
With the provided code, I get an error of:
prog.cpp:26: error: no matching function for call to ‘Run(bool (Base::*)())’
(you can fiddle with the snippet at http://ideone.com/8NZkq):
#include <iostream>
class Base {
public:
bool foo() { return true; }
};
Base* x;
template<typename T>
struct Traits {
typedef bool (T::*BoolMethodPtr)();
};
template<typename T>
void Run(typename Traits<T>::BoolMethodPtr check) {
T* y = dynamic_cast<T*>(x);
std::cout << (y->*check)();
}
int main() {
Base y;
x = &y;
Run<Base>(&Base::foo);
Run(&Base::foo); // why error?
}
The T in Traits<T>::BoolMethodPtr is in a non-deduced context, so the compiler will not deduce automatically from the call what type T should be.
This is because there could be code like this:
template<typename T>
struct Traits {
typedef bool (T::*BoolMethodPtr)();
};
template<>
struct Traits<int> {
typedef bool (Base::*BoolMethodPtr)();
};
Run(&Base::foo); /* What should T be deduced to? Base and int are both equally possible */
If you can do without the Traits<T> class, you can write Run as:
template<class Class>
void Run(bool (Class::*check)()) {
Class* y = dynamic_cast<Class*>(x);
std::cout << (y->*check)();
}
In this context, Class can be deduced to mean Base
To pick apart a type, any type, use partial specialization. There is no function template partial specialization, so you'll need to directly parameterize the function on its argument type and retrieve the class type inside.
template< typename T >
struct get_host_class; // most types are not ptmfs: don't implement this
template< typename C >
struct get_host_class< bool (C::*)() > { // implement partial specialization
typedef C host;
typedef void sfinae; // disallow function for non ptmf arguments
};
template< typename T >
typename get_host_class<T>::sfinae Run( T check) {
typedef T BoolMethodPtr; // or something
typedef typename get_host_class< T >::host host;
}
I think this is a non deduced context.
$14.8.2.5/5- "The non-deduced contexts
are: — The nested-name-specifier of a
type that was specified using a
qualified-id."
I think this is the quote that applies in this case. But some template gods need to ratify my understanding.
When the compiler tries to match a template argument, it only considers the primary class type. In other words, when it encounters the expression:
Run(&Base::foo);
...and it's trying to figure out the template parameter for Run, it only considers the type of foo itself, and doesn't consider whatever class foo is a part of.
EDIT:
And the type of foo is bool(Base::*)(void), but what you want the compiler to find is just Base