getting key_type from value_type - c++

I have a class X that operates on std containers. A function that takes a value_type as argument must call a function that takes a key_type as argument. How do I do that? I seems so basic.
template<typename C>
class X
{
void foo(typename C::value_type vt)
{
bar(vt.first); // this works for C = std::map
bar(vt); // this works for C = std::set
}
void bar(typename C::key_type kt)
{
...
}
};

Add a (private) bar overload that is a function template and takes a T::value_type as argument.
template<typename C>
class X
{
public:
void foo(typename C::value_type vt)
{
bar(vt);
}
void bar(typename C::key_type kt)
{}
private:
template<typename T = C>
void bar(typename T::value_type kt)
{
bar(kt.first);
}
};
When C is an std::map, the call to bar within foo will resolve to the member function template, and it'll then call other bar with the correct argument.
When C is an std::set, the call to bar will match both the bar overloads, but since one is a member function template, and the other isn't, the latter will be considered a better match.
Live demo

Related

How do you specialize a member function inside a template class?

Let's say I have the following class:
template <typename T>
class SomeClass : Parent<T>
{
public:
// I have a function such as this one:
T DoSomething(const T &t)
{
return t.DoSomething(some_data);
}
// But `T` might be a pointer, so sometimes I will need something like the following
// instead (which obviously doesn't work as given):
T DoSomething(const T &t)
{
return new T(t->DoSomething(some_data));
}
private:
XYZ some_data;
};
I got stuck in a giant mess of template errors trying to implement this in any semi-nice way possible using template specialization.
In the end I came up with this very ugly solution:
template <typename T>
class SomeClass : Parent<T>
{
public:
T DoSomething(const T &x)
{
return Specializer<T>::Do(this, x);
}
private:
template <typename V>
struct Specializer {
static V Do(SomeClass *me, const V &x)
{
return x.DoSomething(me->some_data);
}
};
template <typename V>
struct Specializer<V*> {
static V* Do(SomeClass *me, const V *&x)
{
return new V(x->DoSomething(me->some_data));
}
};
XYZ some_data;
};
Is there a better way to do this that doesn't involve stuffing this function into a dummy class/struct and passing around my this pointer?
PS: In reality, this has nothing to do with pointers, but rather with different types of containers. Pointers were just an easy example to use here.
You can avoid writing any specializations, and use a type trait like std::is_pointer along with if constexpr to decide what code to execute depending on the whether the type is a pointer type or not:
auto DoSomething(const T &t)
{
if constexpr (std::is_pointer_v<T>)
return new T(t->DoSomething(some_data));
else
return t.DoSomething(some_data);
}
If you don't want to check for whether T is a pointer, but want to check something else, you can still use this pattern by dropping in a suitable replacement for is_pointer.
If you have access to c++20, you can clean up the need for any SFINAE, specializations, or if constexpr by using concepts and constraints instead. This just allows you to define the same function N times with different criteria for its insantiation, which is much more readable IMO.
This is almost the same as the SFINAE approach, but without the need for the awful syntax (no std::declval, decltype, etc). It also doesn't require all implementations to exist in one function definition like the if constexpr approach; all you need is separate function definitions with different requires clauses:
#include <concepts>
...
template <typename T>
class SomeClass : Parent<T>
{
public:
// Work for everything that's not specialized
void DoSomething(const T &t)
{
std::cout << "Basic overload" << std::endl;
}
// Only work for pointers
void DoSomething(const T& t) requires(std::is_pointer_v<T>)
{
std::cout << "Pointer overload" << std::endl;
}
// Only work if T is convertible to SomeType
void DoSomething(const T& t) requires(std::convertible_to<T, SomeType>)
{
std::cout << "Convertible to SomeType overload" << std::endl;
}
private:
XYZ some_data;
};
Live Example
In this approach there are 3 different entries:
The basic fallback for all templates
An implementation that works for any pointer type, and
An implementation that works for any T type that may be convertible to SomeType
What about using SFINAE?
For example
#include <utility>
#include <iostream>
template <typename>
struct Parent
{ };
using XYZ = int;
template <typename T>
class SomeClass : Parent<T>
{
public:
template <typename U = T>
auto DoSomething (T const & t)
-> decltype( std::declval<U>().DoSomething(std::declval<XYZ>()) )
{ std::cout << "ref\n"; return t.DoSomething(some_data); }
template <typename U = T>
auto DoSomething (T const & t)
-> std::remove_reference_t<
decltype( std::declval<U>()->DoSomething(std::declval<XYZ>()),
std::declval<T>() )>
{
using V = std::remove_reference_t<decltype(*t)>;
std::cout << "pnt\n"; return new V(t->DoSomething(some_data));
}
private:
XYZ some_data;
};
struct foo
{
foo (foo*) {}
foo () {}
foo DoSomething (int) const { return {}; }
} ;
int main()
{
SomeClass<foo> sc1;
SomeClass<foo*> sc2;
foo f;
sc1.DoSomething(f);
sc2.DoSomething(&f);
}
I mean: what about enabling the first version if, and only if, T is a type that supports a DoSomething(XYZ) method and enabling the second version if, and only if, T is a pointer of a type that supports a DoSomething(XYZ) method?

template static function template class type deduction

I want to make static function in singletone template class, that would be able to deduct types of template class.
The problem is, that calling static function from template class requires explicit type.
The only workaround that I've came up with was template function instead if template member function.
Here is an example. The problem is that foo4 part is not working
template <class T>
class Foo
{
private:
Foo() {}
Foo(const Foo&) = delete;
Foo& operator= (const Foo&) = delete;
public:
static auto& Instance()
{
static Foo foo{};
return foo;
}
template<class K> static
auto& DeductInstance(const K&)
{
static Foo<K> foo{};
return foo;
}
};
template<class K>
auto& DeductInstance(const K&)
{
return Foo<K>::Instance();
}
void main()
{
auto& foo1 = Foo<int>::Instance(); //OK
auto& foo2 = Foo<int>::Instance(); //OK (return same example as foo1)
auto& foo3 = DeductInstance(123); //OK
auto& foo4 = Foo::DeductInstance(123); //NOT WORKING
}
The syntax you're asking for is theorically possible using injected class names. That would make Foo:: resolve to a particular, unrelated Foo<x>::. Here's an example:
struct BaseFoo {
template<class K> static
auto& DeductInstance(const K&);
};
template <class T>
struct Foo {
static auto& Instance() {
static Foo foo{};
return foo;
}
};
template<>
struct Foo<void> : private BaseFoo {
using BaseFoo::DeductInstance;
};
template<typename K>
auto& BaseFoo::DeductInstance(const K&)
{
return Foo<K>::Instance();
}
using MakeFooAvailable = Foo<void>;
struct Dummy : MakeFooAvailable {
auto& bar() {
// Syntax working
return Foo::DeductInstance(234);
}
};
In the class Dummy, there's a injected class name for the base class Foo, resolving it to Foo<void>. Then, Foo<void> is making BaseFoo::DeductInstance available for name resolution in its scope.
I would advise not using this solution because it's a clever one. Clever generally mean surprising. Programmers don't expect seeing Foo as a non template when it is. The best solution I think would be:
auto& foo1 = Foo<int>::Instance(); //OK
The simpler, the better.
I have to admit that I dont understand completely what you are trying to do. However, you can do either of the following two:
struct foo {
template <typename T>
static T deduce(const T& t) {
return {};
}
};
template <typename T>
T deduce_free(const T& t) {
return {};
}
int main() {
auto x = foo::deduce(1);
auto y = deduce_free(1);
}
But you cannot call a method (whehter static or not) on some instance of bar<T> before you know what T is.
Things have changed a bit with C++17 which has class template argument deduction, though as far as I know this works for constructors, so you would still need a foo<int> first before you could call a foo<int>::deduce() I am too unexperienced with that to say something not wrong ;).
It's 2021 and we have CTAD, but I don't think it helps. I think this is very close to what you (and I!) want:
// A helper struct to provide Foo with a default template
// that isn't useful for instantiation:
struct DoNotInstantiate { DoNotInstantiate() = delete; };
template <class T = DoNotInstantiate>
class Foo
{
private:
Foo() {
static_assert(!std::is_same_v<T, DoNotInstantiate>, "You can't actually instantiate it with the default, it's just to make the static function work."); // Optional
}
// ...
public:
// ...
template<class K> static
auto& DeductInstance(const K&)
{
static Foo<K> foo{};
return foo;
}
};
So you can call Foo<>::DeduceInstance(bar);. You still have to write the <> but otherwise, it's perfect, I think.
If you don't want that and really want to be able to call a static on a template, naming just the template name, there's this:
template <template<typename ...> class FooType, typename T>
auto DeduceInstance(const T& x) {
return FooType<T>::DeduceInstance(x);
}
which lets you call DeduceInstance<Foo>(x) where Foo is just a template. But that feels round-about. I prefer Foo<>::DeduceInstance(x);.
It would be nice if CTAD let you write
template <class T>
Foo::DeductInstance(const T&) -> T&;
or maybe it would be
template <class T>
Foo::DeductInstance(const T&) -> Foo<T>::DeduceInstance(const T&);
or something similar, basically saying that if you use the template name without a type to call a static, use the argument list to dope out which template the caller was talking about.

polymorphic arguments in a function pointer in C++

Is it possible to safely cast between two function pointer in C++, given that the arguments as polymorphicly equivalent i.e. (example only)
class Base {}
class A : Base {}
class B : Base {}
class C : Base {}
template<typename T, typename U>
using FPTR = void (*)(const T&, const U&);
using index = std::pair<std:type_info, std::type_info>;
std::unordered_map<index, FPTR<Base, Base>> func_map;
template<typename T, typename U>
register(FPTR<T,U> fptr) {
// assert T and U are subclasses of Base
func_map[index(typeid(T), typeid(U))] = fptr;
}
void call(const Base& first, const Base& second) {
auto it = func_map.find(index(typeid(first), typeid(second)));
if (it != func_map.end()) {
(*it)(first, second)
}
}
void func1(const A&, const C&) {}
// call these
register<A,C>(func1);
register<B,B>([](const B&, const B&) -> void {});
so when invoking call, it would resolve the function to call based on the registered typeids, and the called function would expect the explicit type, effectively casting from the base type.
My thinking is this is going to cause an error at run time because the cast wron't occur correctly. I've considered using a lambda function to wrap fptr, but that would result in an extra indirect call, is there a way to avoid this while correctly performing the cast, note I can't cast in call, because I can only get the typeid/type_info and can't use that with the cast functions.
You can do it with an extra direct call, if that's not a problem (the target call might even be in-lineable in the wrapper, depending on your compiler and how the translation units are set up).
Something like:
struct Base {}
// ...
template <typename T, typename U>
using FPTR = void (*)(const T&, const U&);
template <typename T, typename U, FPTR<T,U> fptr>
void WrapFPTR(const Base &a, const Base &b)
{
fptr(static_cast<const T&>(a), static_cast<const U&>(b));
}
allows you to store WrapFPTR<T,U,foo> which is an FPTR<Base,Base> at every site where you register a given function foo.
If you really need an arbitrary function pointer, you'd need to store a polymorphic closure object with a pointer to that function's concrete type instead.
Current C++ contains no elaborate notion of co(ntra)variance. Can you go with static mapping instead?
#include <iostream>
class Base {};
class A : Base {};
class B : Base {};
class C : Base {};
template<typename T, typename U> using FPTR = void (*)(const T&, const U&);
// instead of allocating a run-time map, create a map on compiler's heap at compile-time
template<typename U, typename V> static FPTR<U const &, V const &> funcMap;
void nyan(A const &, A const &) { std::cout << "Nyan" << std::endl; }
void meow(B const &, B const &) { std::cout << "Meow" << std::endl; }
int main() {
funcMap<A, A> = nyan;
funcMap<B, B> = meow;
funcMap<A, A>(A{}, A{});
}

Is there a way to do this using templated functions in c++

I'm currently writing some code to convert java code to c++ code and consequently ending up with some pretty hairy issues. My question is, is it possible to have an overloaded operator that returns the templated value from the containing class?
Ie: I want to be able to do the following with the following classes.
SmartPointer<ArrayClass<bool>*> boolArray = new ArrayClass<bool>(true, true, false, false);
bool b = boolArray[1];
template <typename T> class SmartPointer
{
T data;
template <typename U>
U operator [](int i) const
{
return ((*T)(*data))[index];
}
}
template ArrayClass<U>
{
// Various constructors...
U operator [](int i) const
{
// Implementation here
}
}
The problem I get (understandably) is:
error C2783: 'U SmartPointer::operator const' : could not deduce template argument for 'U'
The compiler doesn't know what U is and I want to be able to tell it that it's bool - because this is what the ArrayClass will be returning. The SmartPointer might not contain an array, in which case the [] operator wouldn't make sense. However I want to be able to pass it through to the object inside the smart pointer in case it does... ?
I don't know what to do to make this work. Perhaps it's not possible??
ANSWER:
Thanks to everyone for responding. There are 3 solutions provided that are essentially the same, but I've award this to Oktalist as he got in first.
I still have a difficulty with this solution though, as I'm passing pointers into my SmartPointer class to allow me to use forward declared classes. This prevented me from using T::value_type as my return type, but that appears to be the right way to do it. It looks like I'm asking to much of the compiler and it looks like I'll have to revert back to simply dereferencing the smartpointer in order to do the array access!
The traditional C++03 way is to use a typedef, typically named value_type. In C++11 we can improve upon this with auto and decltype. Here is your example modified to use both:
SmartPointerCPP03<ArrayClass<bool>> boolArray = new ArrayClass<bool>(true, true, false, false);
SmartPointerCPP11<ArrayClass<bool>> boolArray = new ArrayClass<bool>(true, true, false, false);
bool b = boolArray[1];
template <typename T> class SmartPointerCPP03
{
T* data;
typename T::value_type operator [](int i) const
{
return (*data)[i];
}
}
template <typename T> class SmartPointerCPP11
{
T* data;
auto operator [](int i) const -> decltype(std::declval<T>()[i])
{
return (*data)[i];
}
}
template <typename T> class SmartPointerCPP14
{
T* data;
auto operator [](int i) const
{
return (*data)[i];
}
}
template <typename U> ArrayClass
{
// Various constructors...
typedef U value_type;
U operator [](int i) const
{
// Implementation here
}
}
I also took the liberty of changing T data to T* data and removing the * from the parameter in the instantiation. By the way, your (T*) cast was wrong, and I removed that too.
To start with, make the SmartPointer accept the non-pointer type:
SmartPointer<ArrayClass<bool> > boolArray = new ArrayClass<bool>(true, true, false, false);
Add a typedef to the ArrayClass:
template <typename U> class ArrayClass
{
typedef U value_type;
...
};
Then write a metafunction to get the type:
template <typename T> struct ValueTypeOf {
typedef typename T::value_type type;
};
Then use this in the SmartPointer:
template <typename T>
class SmartPointer
{
typedef typename ValueTypeOf<T>::type value_type;
T* data;
value_type operator [](int i) const
{
return ((*data))[index];
}
};
By using the ValueTypeOf metafunction, you can specialize it based upon the type, so if your type does not have a value_type member, you can do something different to get at it.
Edit: to specialize for a pointer type example:
struct A {
typedef int value_type;
};
template <typename T>
struct ValueTypeOf
{
typedef typename T::value_type type;
};
template <typename T>
struct ValueTypeOf<T*>
{
typedef typename T::value_type type;
};
int main()
{
ValueTypeOf<A>::type foo = 0; // foo is an int
ValueTypeOf<A*>::type bar = 0; // bar is an int
return 0;
}
It's been a while, but I used to do a lot of this. Something like the following should work:
Define a typedef in ArrayClass called value_type, and typedef U to that. Then use T::value_type as the return type of operator [] in SmartPointer.

How to have std::function or lambda as (optional) template parameter?

Hi I was playing around with TMP and was thinking of generating of a class
that looks something like:
template<typename T, typename LogFunc>
class
{
(where LogFunc should be defaulted to "nop" function)
Idea is to have a class that defines some functionality for instances of type T, for example checks if the number is even, and also has the option to log by calling
void memberFunc(T& t)
{
LogFunc(t);
}
or maybe
void memberFunc(T& t)
{
LogFunc lf;
lf(t);
}
Can it be done?
From reading A on SO, lambdas are kind of problematic as templ params.
BTW if somebody cares this is what I tried but it prints out
:(
The problem is that the type of a lambda is a compiler-enforced singleton; it has only one value, which is the lambda itself; furthermore, the type has a deleted constructor. So you can't pass lambdas as part of a template instantiation, even with decltype. But there's nothing stopping you from passing them as constructor arguments.
However, here we run into another problem: constructor arguments are not used to deduce a template instantiation (which is why the standard library provides utilities like make_pair and make_tuple). So we need a templatized factory function.
With all that, the solution is pretty simple:
template<typename T, typename LogFunc>
class Foo {
public:
Foo(const T& t, LogFunc fn) : t_(t), lfn_(fn) {}
//...
private:
T t_;
LogFunc lfn_;
};
struct Noop {
template<typename...A>
void operator()(A...) { };
};
template<typename T, typename LogFunc=Noop>
Foo<T, LogFunc> make_foo(const T& t, LogFunc func=LogFunc()) {
return Foo<T, LogFunc>(t, func);
}
This will not answer directly, but gives a number of hints about what you did.
The LogFunc parameter is a type (not an object), hence
LogFunc(t) creates a temporary LogFunc giving t as parameter (you are in fact calling the LogFunc::LogFunc(T&) contructor).
LogFunc lf; lf(t); creates a stack-living default contructed Logfunc, named lf, and lf(t) calls its LogFunc::operator()(T&) member function.
LogFunc()(t) creates a temporary default-constructed LogFUnc and calls operator()(T&) on it.
About lambdas, they are in fact classes whose constructor takes the captured varaibles, and whose operator() takes the parameters you declare. But they exist only "internaly" to the compiler, and don't have a "name" you can refer to.
What you can do is deduce its type with a decltype, or with a free-function.
Typically a parametric functional class stores a frunction object, initialized at construction.
#include <iostream>
template<class Fn>
class LogFunc
{
public:
LogFunc(Fn f) :fn(f) {}
template<class T>
void memberFunc(T& t)
{ fn(t); }
private:
Fn fn;
};
template<class Fn>
LogFunc<Fn> makeLogFunc(Fn f)
{ return LogFunc<Fn>(f); }
int main()
{
int x=5;
auto lf = makeLogFunc([](int& a){ std::cout << a << std::endl; });
lf.memberFunc(x);
return 0;
}
compile as "g++ -pedantic -Wall -std=c++11", and will ouptut
5
The other answers are all fine, but you can also just pass in a constructor argument with a std::function<T>. That looks like this:
#include <functional>
#include <iostream>
template <typename T> void someOther(T val){
std::cout << "used other "<<val<<std::endl;
}
template <typename T> void noop(T val){
std::cout << "noop "<<val<<std::endl;
}
template<typename T>
struct A{
A(std::function<void(T)> f =noop<T> ) : mf(f){}
void memberFunc(T valx){
mf(valx);
}
std::function<void(T)> mf;
};
int main(){
A<int> aNoop; ;
A<float> aSomeOther{someOther<float>} ;
aNoop.memberFunc(5);
aSomeOther.memberFunc(3.55);
}
An alternative is to use functor classes, like this:
#include <iostream>
template <typename T> struct OtherC{
void operator()(T v){ std::cout <<"other "<<v<<std::endl; };
};
template <typename T> struct NoopC{
void operator()(T){ std::cout << "noop"<<std::endl; };
};
template<typename T, template <typename X> class F = NoopC >
struct A{
static void memberFunc(T valx){ F<T>()(valx); }
};
int main(){
A<int> aNoop;
A<float,OtherC> aSomeOther ;
aNoop.memberFunc(5);
aSomeOther.memberFunc(3.55);
}