Writing at alias template that will deduce the return type of some type T's operator->, so far I have this
template <typename T>
using arrow = decltype(std::declval<T&>().operator->());
which works for all class types, but doesn't work for pointers. A similar problem exists trying to actually call the ->
template <typename T>
struct D {
T t;
arrow<T> f() {
// not valid to call .operator->() on pointers
return t.operator->();
}
};
How can I make this function get the correct return type declared, and delegate correctly for both class types and pointers?
For a pointer, the type of its operator->() its own type, and the resulting object has its same value. With another level of indirection, a helper struct can be specialized for pointer types
template <typename T>
struct ArrowHelper {
using type = decltype(std::declval<T&>().operator->());
type operator()(T& t) const {
return t.operator->();
}
};
template <typename T>
struct ArrowHelper<T*> {
using type = T*;
constexpr type operator()(T* t) const noexcept {
return t;
}
};
To simplify usage, an alias template and a function can be defined easily
template <typename T>
using arrow = typename ArrowHelper<T>::type;
template <typename T>
arrow<T> apply_arrow(T& t) {
return ArrowHelper<T>{}(t);
}
the delegating member function then becomes
template <typename T>
struct D {
T t;
arrow<T> f() { return apply_arrow(t); }
};
Related
Consider passing a callable class template as a template parameter to some class. Three approaches as below but only functor one works.
The naive template function failed because it cannot serve as a class template; However, why the C++20 familiar template lambda fails? https://godbolt.org/z/MaYdqx1do
template <typename T>
T SomeFunc() {
return T{};
}
template <typename T>
struct SomeFunctor {
T operator()() const { return T{}; }
};
auto SomeLambda = []<typename T>() { return T{}; };
template <template <typename> class F>
struct Foo {
int operator()() const { return F<int>()(); }
};
int some_func_result = Foo<decltype(&SomeFunc)>()(); // cannot compile
int some_functor_result = Foo<SomeFunctor>()();
int some_lambda_result = Foo<decltype(SomeLambda)>()(); // cannot compile
Let me answer my own question. Familiar template lambdas(introduced in c++ 20) are like anonymous functors(function object) but templated on the operator instead of on the class. It essentially translates to below functor class in theory. Therefore there's no way for the user class to apply it as a class template for its template argument. https://godbolt.org/z/1TddKan6n
auto SomeLambda = []<typename T>() { return T{}; };
struct SomeLambdaGut {
template <typename T>
T operator()() const { return T{}; }
};
I have a function that takes in a std::function as a parameter. However, I want to ensure the function being passed in is not allowed to modify the parameters passed to it.
Here's the simple version of the function (note that T can be, and usually is, a reference):
template <class T>
void Bar(std::function<void(std::add_const_t<T>)> func)
{
// ...
}
Bad usage:
Bar<int&>([](int&) { /* Do nasty stuff! */ }); /* A-OK! */
I want to disallow that usage, but this code compiles perfectly fine, even though I feel like it shouldn't.
Interesting thing is, if I get rid of the template parameter, i.e.:
void Bar(std::function<void(const int&)> func)
{
// ...
}
Then, this usage wouldn't compile (as it shouldn't):
Bar([](int&) { /* Do nasty stuff! */ }); /* Error C2664 */
How can I enforce this and still keep the template parameter?
Note that std::add_const_t<int &> is int &, for you are not adding const to int. Instead you are adding const to a reference to int and you obtain a const reference to int (that is int &), not a reference to a const int.
A simple way to work around it can be:
#include<functional>
#include<type_traits>
template<typename T>
struct to_const_ { using type = std::add_const_t<T>; };
template<typename T>
struct to_const_<T &> { using type = std::add_const_t<T> &; };
template<typename T>
using to_const_t = typename to_const_<T>::type;
template <class T>
void Bar(std::function<void(to_const_t<T>)> func)
{}
int main() {
Bar<int&>([](int&) {});
}
The code above doesn't compile (as requested), unless you turn it to:
Bar<int&>([](const int &) {});
Note that it works correctly only with lvalue references as it stands, but adding the support for rvalue references and pointers is straightforward if you got the idea.
It follows a minimal, (probably) working example:
#include<functional>
#include<type_traits>
template<typename T>
struct to_const_ { using type = std::add_const_t<T>; };
template<typename T>
struct to_const_<T &> { using type = std::add_const_t<T> &; };
template<typename T>
struct to_const_<T &&> { using type = std::add_const_t<T> &&; };
template<typename T>
struct to_const_<T * const> { using type = std::conditional_t<std::is_pointer<T>::value, typename to_const_<T>::type * const, std::add_const_t<typename to_const_<T>::type> * const>; };
template<typename T>
struct to_const_<T *> { using type = std::conditional_t<std::is_pointer<T>::value, typename to_const_<T>::type *, std::add_const_t<typename to_const_<T>::type> *>; };
template<typename T>
using to_const_t = typename to_const_<T>::type;
template <class T>
void Bar(std::function<void(to_const_t<T>)> func)
{}
int main() {
Bar<int **>([](const int **) {});
}
You can use static_assert to make compilation fail, with help from templates.
//Base case - T is non-const, possibly pointer or reference
template <typename T> struct is_const_param { static constexpr bool value = !std::is_lvalue_reference<T>::value && !std::is_rvalue_reference<T>::value && !std::is_pointer<T>::value; };
//T is const, but possibly pointer to non-const
template <typename T> struct is_const_param<const T> { static constexpr bool value = !std::is_pointer<T>::value; };
//Remove reference, try again
template <typename T> struct is_const_param<const T&> : is_const_param<const T> { };
//Remove reference, try again
template <typename T> struct is_const_param<const T&&> : is_const_param<const T> { };
//Remove pointer, try again
template <typename T> struct is_const_param<const T*> : is_const_param<const T> { };
//Remove pointer, try again
template <typename T> struct is_const_param<const T* const> : is_const_param<const T> { };
The static_assert would just look like:
template <class T>
void Bar(std::function<void(T)>)
{
static_assert(is_const_param<T>::value, "...");
}
This is set up to only succeed when T is:
Passed by value (see below).
Passed by constant reference.
Passed by pointer(s) to constant.
You can see some test cases here if you want to see examples of what makes it succeed or fail.
This was set up to allow passing by value normally, like Bar<int>. If you want to change it to only allow Bar<const int>, remove the is_const_param<const T*> specialization and change the initialization of value in the unspecialized template to false. You can see that here.
I have this method
template <typename T>
T GetFnInput(){
//.... here is obtained void * t value from some library
return (T)(t);
}
And I have several template specializations for different types
template <>
uint32 GetFnInput<uint32>(){
return 0;
}
template <>
bool GetFnInput<bool>(){
return true;
}
However, I need a specialization for reference. I have tried this (the code is mess and should not be used in production, this is just for my testing purposes):
template <typename T,
typename BaseT = std::decay<T>::type,
typename std::enable_if <std::is_reference<T>::value == true>::type* = nullptr >
T GetFnInput(){
BaseT * t = new BaseT();
return *t;
}
Plus I have add typename std::enable_if <std::is_reference<T>::value == false>::type* = nullptr > to original (above) GetFnInput()
But it wont compile, end with error:
error C2244: 'GetFnInput': unable to match function definition to an
existing declaration
First problem is that you're missing typename here:
typename BaseT = std::decay<T>::type,
^^^
Once you have that, you have a second problem which is that the call to, say, GetFnInput<int&>() is ambiguous between the original function template GetFnInput<typename> and this new function template GetFnInput<typename, typename, typename>. These two function templates are overloads of each other and are otherwise unrelated.
Typically want you want to do is lift the template parameter into the argument list so it becomes easier to overload on:
template <class T> struct tag { using type = T; };
template <class T>
auto get() -> decltype(get_impl(tag<T>{}))
{
return get_impl(tag<T>{});
}
And then you can write your get_impl function template much easier. Specific types are just specific overloads:
uint32_t get_impl(tag<uint32_t> ) { return 0; }
And reference types is just a template:
template <class T>
T& get_impl(tag<T& > ) { ???; }
Note that return a reference to an allocated pointer sounds like a really bad idea.
You try is an overload, not a specialization.
As function cannot be partial specialized, I suggest to use struct instead:
template <typename T>
struct helper
{
T operator() const { return {}; }
};
template <>
struct helper<bool>
{
bool operator() const { return true; }
};
template <typename T>
struct helper<T&>
{
T& operator() const { static T t; return t; }
};
template <typename T>
T GetFnInput(){
return helper<T>{}();
}
I want to define a template class with 2 template arguments:
A pointer type T*
A pointer to a member function of the underlying type T
Additionally I would like to set a default method for the function argument.
// Do not allow SortedLinkedList<T>
template<typename T, bool (T::* comparisonMethod)(const T&) = &T::lessEqual>
class SortedLinkedList
{
private:
SortedLinkedList();
};
// Allow SortedLinkedList<T*>
template<typename T, bool (T::* comparisonMethod)(const T&)>
class SortedLinkedList<T*>
{
public:
void insert(T* item)
{
// do something with /item->*comparisonMethod)(...))
}
};
This code does not compile, because g++ (4.4.3) can not deduce the underlying type of T*
error: creating pointer to member function of non-class type ‘T*’
Is there a way to deduce the underlying type already in the class declaration? decltype is not available in C++03 and I don't know if it would work at this place.
I've found this answer, but it does not help in this case.
Thanks
The Problem
The reason it fails to compile is that the compiler will check to see that the primary-template is a viable match before it goes on to see if there is any specialization that is a more suitable alternative.
This means that when you try to instantiate SortedLinkedList<A*>, the compiler tries to see if the declaration bool (T::* comparisonMethod)(const T&) = &T::lessEqual, in the primary-template, is well-formed having T = A* - which it obviously isn't (since pointers can't have member-functions).
A Solution
One way to solve this issue is to add a level of indirection, so that both the primary template - and the specialization - yields a well-formed instantiation.
template<class T> struct remove_pointer { typedef T type; };
template<class T> struct remove_pointer<T*> { typedef T type; };
template<class T>
struct comparison_method_helper {
typedef typename remove_pointer<T>::type Tx;
typedef bool (Tx::*type)(Tx const&) const;
};
// primary-template
template<
class T,
typename comparison_method_helper<T>::type = &remove_pointer<T>::type::lessEqual
> class SortedLinkedList;
// specialization
template<typename T, typename comparison_method_helper<T>::type func>
class SortedLinkedList<T*, func> {
public:
void insert (T const& item) {
(item.*func) (T ());
}
};
#include <iostream>
struct A {
bool lessEqual (A const&) const {
std::cerr << "hello world\n";
return false;
}
};
int main () {
SortedLinkedList<A*> ().insert (A()); // outputs 'hello world'
}
Is it possible to return type of an object? For example I would like to have construct like this:
//pseudocode
template<class T>
void f(int value)
{
//depends on type T different action can be taken
}
template<class T>
type getType(T obj)
{
return (type of obj);
}
and then in main:
f<getType(Object)>(value);
Yes in some sense, but you need to move T into a parameter. This is the conditional trick explored by Eric Niebler and explained here.
template<typename T>
struct id { typedef T type; };
template<typename T>
id<T> make_id(T) { return id<T>(); }
struct get_type {
template<typename T>
operator id<T>() { return id<T>(); }
};
#define pass_type(E) (true ? get_type() : make_id((E)))
pass_type(expression) yields an id<T> object such that T is the cv-unqualified type of that expression. So you can do
template<class T>
void f(int value, id<T>)
{
// Now go on as usual on T
}
f(value, pass_type(Object));
In C++0x there is decltype and auto that can be used
In template metaprogramming, this is normally done via class templates.
template <typename T>
struct GetType
{
typedef T type; // usually it's something more complex
};
// example: partial specialization is used to compute element type of some container template
template <typename T>
struct GetType< MyContainerType<T> >
{
typedef T type;
};
.........................
// and now you use it:
f<GetType<Object>::type>(value);
Here, struct GetType<T> can be thought of as a (meta)function taking one type argument and returning one type value.
I think that you just need to use function template specialization:
template<>
void f(int value)
{
.. operations when an int
}
template<>
void f(char value)
{
.. operations when a char
}
template<>
void f(double value)
{
.. operations when a double
}
template<class T>
void f(T value)
{
.. operations when a T (not int, char or double)
}