template friend function: wrong function called - c++

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;
}

Related

Template function deduction fail on std::conditional argument

Please, before marking this as a duplicate of This question read the entirety of the post
This piece of code fails to compile, with a template deduction error:
#include <iostream>
#include <type_traits>
template<typename T = float, int N>
class MyClass
{
public:
template<typename DATA_TYPE>
using MyType = std::conditional_t<(N>0), DATA_TYPE, double>;
MyType<T> Var;
void Foo()
{
Bar(Var);
}
template<typename TYPE>
void Bar(MyType<TYPE> Input)
{
std::cout << typeid(Input).name() << std::endl;
}
};
int main()
{
MyClass<float, 1> c;
c.Foo();
return 0;
}
I understand the point that was made in the question i linked above, which is that "the condition which allows to choose the type to be deduced depends on the type itself", however, why would the compiler fail in the specific case i provided as the condition here seems to be fully independent from the type, or is there something i'm missing?
I would be more than happy if someone could refer to a section of the c++ standard that would allow me to fully understand this behaviour.
As the linked question, TYPE is non deducible. MyType<TYPE> is actually XXX<TYPE>::type.
You have several alternatives, from your code, I would say one of
Bar no longer template:
template<typename T = float, int N>
class MyClass
{
public:
template<typename DATA_TYPE>
using MyType = std::conditional_t<(N>0), DATA_TYPE, double>;
MyType<T> Var;
void Foo()
{
Bar(Var);
}
void Bar(MyType<T> Input)
{
std::cout << typeid(Input).name() << std::endl;
}
};
requires (or SFINAE/specialization for pre-c++20):
template<typename T = float, int N>
class MyClass
{
public:
template<typename DATA_TYPE>
using MyType = std::conditional_t<(N>0), DATA_TYPE, double>;
MyType<T> Var;
void Foo()
{
Bar(Var);
}
template<typename TYPE>
void Bar(TYPE Input) requires(N > 0)
{
std::cout << typeid(Input).name() << std::endl;
}
void Bar(double Input) requires(N <= 0)
{
std::cout << typeid(Input).name() << std::endl;
}
};

How to specialise template method with type that itself is a template where only the return type relies on the template type?

I want to specialise a single template method in a non-template class to use an std::vector however only the return type of the method uses the template.
#include <iostream>
#include <string>
#include <vector>
class Foo
{
public:
template<typename T>
T Get()
{
std::cout << "generic" << std::endl;
return T();
}
};
template<>
int Foo::Get()
{
std::cout << "int" << std::endl;
return 12;
}
template<typename T>
std::vector<T> Foo::Get()
{
std::cout << "vector" << std::endl;
return std::vector<T>();
}
int main()
{
Foo foo;
auto s = foo.Get<std::string>();
auto i = foo.Get<int>();
}
This compiles with an error indicating that the std::vector attempted specialisation does not match any prototype of Foo, which is completely understandable.
In case it matters, use of C++14 is fine and dandy.
You can only partially specialize classes (structs) (cppreference) - so the way to overcome your problems is to add helper struct to allow this partial specialization of std::vector<T> - e.g. this way:
class Foo
{
private: // might be also protected or public, depending on your design
template<typename T>
struct GetImpl
{
T operator()()
{
std::cout << "generic" << std::endl;
return T();
}
};
public:
template<typename T>
auto Get()
{
return GetImpl<T>{}();
}
};
For int - you can fully specialize this function:
template<>
int Foo::GetImpl<int>::operator()()
{
std::cout << "int" << std::endl;
return 12;
}
For std::vector<T> you have to specialize entire struct:
template<typename T>
struct Foo::GetImpl<std::vector<T>>
{
std::vector<T> operator()()
{
std::cout << "vector" << std::endl;
return std::vector<T>();
}
};
Partial specialisation of template functions (including member functions) is not allowed. One option is to overload instead using SFINAE. For example,
/// auxiliary for is_std_vetor<> below
struct convertible_from_std::vector
{
template<typename T>
convertible_from_std::vector(std::vector<T> const&);
};
template<typename V>
using is_std_vector
= std::is_convertible<V,convertible_from_std_vector>;
class Foo
{
public:
template<typename T, std::enable_if_t< is_std::vector<T>::value,T>
Get()
{
std::cout << "vector" << std::endl;
return T();
}
template<typename T, std::enable_if_t<!is_std::vector<T>::value,T>
Get()
{
std::cout << "generic" << std::endl;
return T();
}
};
Note that the helper class is_std_vector may be useful in other contexts as well, so it worth having somewhere. Note further that you can make this helper class more versatile by asking for any std::vector or specific std::vector<specific_type, specific_allocator>. For example,
namespace traits {
struct Anytype {};
namespace details {
/// a class that is convertible form C<T,T>
/// if either T==AnyType, any type is possible
template<template<typename,typename> C, typename T1=Anytype,
typename T2=Anytype>
struct convCtTT
{
convCtTT(C<T1,T2> const&);
};
template<template<typename,typename> C, typename T1=Anytype>
struct convCtTT<C,T1,AnyType>
{
template<typename T2>
convCtTT(C<T1,T2> const&);
};
template<template<typename,typename> C, typename T2=Anytype>
struct convCtTT<C,AnyType,T2>
{
template<typename T1>
convCtTT(C<T1,T2> const&);
};
template<template<typename,typename> C>
struct convCtTT<C,AnyType,AnyType>
{
template<typename T1, typename T2>
convCtTT(C<T1,T2> const&);
};
}
template<typename Vector, typename ValueType=AnyType,
typename Allocator=AnyType>
using is_std_vector
= std::is_convertible<Vector,details::convCtTT<std::vector,ValueType,
Allocator>;
}
You can't partially specialze template in c++. You need to overload your function and pass the type in parameters.
#include <iostream>
#include <string>
#include <vector>
class Foo
{
public:
template<typename T>
T Get()
{
return this->getTemplate(static_cast<T*>(0)); //
}
private:
template<class T> T getTemplate(T* t)
{
std::cout << "generic" << std::endl;
return T();
}
template<class T> std::vector<T> getTemplate(std::vector<T>* t)
{
std::cout << "vector" << std::endl;
return std::vector<T>();
}
};
template <> int Foo::getTemplate(int* t)
{
std::cout << "int" << std::endl;
return 12;
}
int main()
{
Foo foo;
auto s = foo.Get<std::string>();
auto i = foo.Get<int>();
auto v = foo.Get<std::vector<int>>();
}
Edit : fixed a typo in the code

C++ specialise function on enum

Is it possible to specialise a template function on an enum?
I've seen noted here a template function can be disabled if it isn't an enum, but is this possible whilst still allowing other types?
My example below shows specialisations for int, float, and enum (it doesn't compile because it tries to overload the enum version rather than specialising it). I feel I'm missing something obvious.
Note that I'm looking to specialise on any enum, not just a named one (EAnEnum in the example)
#include <iostream>
enum class EAnEnum
{
Alpha,
Beta,
};
template<typename T>
void MyFunc();
template<>
void MyFunc<int>()
{
std::cout << "Int" << std::endl;
}
template<>
void MyFunc<float>()
{
std::cout << "Float" << std::endl;
}
// MyFunc<Enum>
template<typename T>
typename std::enable_if<std::is_enum<T>::value, void>::type MyFunc()
{
std::cout << "Enum" << std::endl;
}
int main()
{
MyFunc<EAnEnum>();
return 0;
}
You cannot partially specialize a function, but you can use tag dispatching instead.
It follows a minimal, working example based on the OP's question:
#include <iostream>
#include<type_traits>
enum class EAnEnum
{
Alpha,
Beta,
};
template<typename>
struct tag {};
void MyFunc(tag<int>)
{
std::cout << "Int" << std::endl;
}
void MyFunc(tag<float>)
{
std::cout << "Float" << std::endl;
}
void MyFunc(tag<EAnEnum>)
{
std::cout << "Enum" << std::endl;
}
template<typename T>
void MyFunc() {
MyFunc(tag<std::decay_t<T>>{});
}
int main()
{
MyFunc<EAnEnum>();
return 0;
}
You can easily add a parameter pack to be forwarded to the right MyFunc and still use this technique to solve your problem.
Of course, you can now specialize for any enum.
You can also provide a fallback MyFunc as:
template<typename T>
void MyFunc(tag<T>)
{
std::cout << "Fallback" << std::endl;
}
If you want a fallback for all the possible enum types, you can now rely on SFINAE, for these are different overloaded functions:
template<typename T>
std::enable_if_t<std::is_enum<T>::value>
MyFunc(tag<T>)
{
std::cout << "Fallback for enums only" << std::endl;
}
Note that you should not use directly the implications of MyFunc that accept a tag specialization as an entry point.
Those are meant as internal functions.
Use instead the generic one, as shown in the example.
You cannot partially specialize a function template, but can you just let it forward to a class template.
Since your function doesn't have arguments that's particularly easy:
#include <iostream>
#include <type_traits>
namespace impl {
using namespace std;
template< class Type, bool is_enum_ = is_enum<Type>::value >
struct Foo;
template< class Type >
struct Foo<Type, true>
{ void func() { cout << "Enum" << endl; } };
template<>
struct Foo<int>
{ void func() { cout << "Int" << endl; } };
template<>
struct Foo<float>
{ void func() { cout << "Float" << endl; } };
} // namespace impl
template< class Type >
void foo()
{ impl::Foo<Type>().func(); }
auto main()
-> int
{
enum class An_enum
{
alpha, beta,
};
foo<An_enum>();
foo<int>();
foo<float>();
#ifdef TEST
foo<char>(); //! Doesn't compile.
#endif
}
With arguments you can use “perfect forwarding” (which isn't all that perfect, really, but usually good enough) via std::forward.

Type trait for extracting template parameter from nested type

I need to get the template parameter from a nested type. Here is a simple example to show the type I need to extract.
#include <iostream>
#include <typeinfo>
template<typename T>
void function(T) {
// T = 'struct A<int>::B'
//
// Here I want to get the template value type e.g. 'int' from T
// so that this would print 'int'. How can this be done?
std::cout << typeid(T).name() << std::endl;
}
template<typename T>
struct A {
using B = struct { int f; };
};
int main() {
function(A<int>::B{});
return 0;
}
You can't extract this through simple deduction. Although B is a nested class of A, the types themselves are unrelated.
One option would be to "save" the type inside B and extract it later:
template<typename T>
struct A {
struct B {
using outer = T;
int f;
};
};
Then you just use typename T::outer to get the type:
template<typename T>
void function(T) {
std::cout << typeid(typename T::outer).name() << std::endl;
}

Invalid use of incomplete type (SFINAE)

I am trying to use some SFINAE inside a templated struct. I reduced my problem to the following and could make this work:
template<bool mybool>
struct test {
void myfunc();
};
template<bool mybool>
void test<mybool>::myfunc() {
std::cout << "test true" << std::endl;
}
template<>
void test<false>::myfunc() {
std::cout << "test false" << std::endl;
}
int main(int argc, char ** argv) {
test<true> foo;
test<false> bar;
foo.myfunc();
bar.myfunc();
}
With this code, I get the result:
test true
test false
However, if I want to consider that my struct test with more than one template parameter, I tried adapting the above like this:
template<int myint, bool mybool>
struct test {
void myfunc();
};
template<int myint, bool mybool>
void test<myint,mybool>::myfunc() {
std::cout << "test true" << std::endl;
}
template<int myint>
void test<myint,false>::myfunc() {
//error: invalid use of incomplete type 'struct test<myint, false>'
std::cout << "test false" << std::endl;
}
int main(int argc, char ** argv) {
test<1,true> foo;
test<1,false> bar;
foo.myfunc();
bar.myfunc();
}
I am getting an invalid use of incomplete type 'struct test'.
Am I going in the wrong direction? Is there a way to do what I want to do?
Thanks for your help!
You cannot partially specialize member function, you should partially specialize full struct. Following example will work correctly
template<int myint, bool mybool>
struct test {
void my_func();
};
template<int myint, bool mybool>
void test<myint,mybool>::my_func() {
std::cout << "test true" << std::endl;
}
template<int myint>
struct test<myint, false> {
void my_func();
};
template<int myint>
void test<myint,false>::my_func() {
//error: invalid use of incomplete type 'struct test<myint, false>'
std::cout << "test false" << std::endl;
}
int main(int argc, char ** argv) {
test<1,true> foo;
test<1,false> bar;
foo.my_func();
bar.my_func();
}
If you want to avoid redefining your class, which you would have to do since partial specialisation of (member) functions is not allowed, you could decompose your type. This will minimise the repetition of code:
template<int myint, bool mybool>
struct test {
char some_var;
std::vector<int> more_var;
void my_func();
};
Change to:
template<int myint>
struct test_static {
protected:
char some_var;
std::vector<int> more_var;
};
template <int myint, bool mybool>
struct test : private test_static<myint> {
void my_func() {
// default case
}
};
template <int myint>
struct test<myint,false> : private test_static<myint> {
void my_func() {
// special case
}
};
Of course, if you want full visibility of all members to the outside, don't make them protected in the first place and use public instead of private inheritance.
Looking first at this question on the SFINAE principle to refresh my memory, I tried to get the result you are looking for with minimal redundancy in the code.
I also checked the wikipedia article on the subject, which indicated me that you need a functionality similar too boost::enable_if to conditionally choose your function inmplementation:
// simplified version of boost::enable_if_c and disable_if_c to match your exact need
template <bool B>
struct enable_if_c {
typedef void type;
};
struct enable_if_c<false>{};
template <bool B>
struct disable_if_c {
typename void type;
};
struct disable_if_c<true> {};
template<bool mybool, typename T>
struct test {
template <bool d>
typename enable_if_c<d>::type my_func_impl(){
cout << "true" << endl;
}
template <bool d>
typename disable_if_c<d>::type my_func_impl(){
cout << "false" << endl;
}
void my_func(){ my_func_impl<mybool>(); }
};
You can define the my_func_impl bodies outside the struct with the following syntax:
template <bool mybool, typename T>
template <bool d>
typename enable_if_c<d>::type test<mybool,T>::my_func_impl(){
cout << "true" << endl;
}
The tricky point of the problem is that you cannot rely on a simple overloading, since you want the same function prototype, hence the need to exclusively define one or the other implementation.
You can add a little improvement to the answer provided by diderc, by just a little modification that enables you to avoid the use of an auxiliary function which would pollute your functions names :
Instead of :
template <bool d>
typename enable_if_c<d>::type my_func_impl(){
cout << "true" << endl;
}
template <bool d>
typename disable_if_c<d>::type my_func_impl(){
cout << "false" << endl;
}
void my_func(){ my_func_impl<mybool>(); }
Just write :
template <bool d = mybool>
typename enable_if_c<d>::type my_func(){
cout << "true" << endl;
}
template <bool d = mybool>
typename disable_if_c<d>::type my_func(){
cout << "false" << endl;
}
And if you can use C++11, then you can replace enable_if_c and disable_if_c by std::enable_if.
( I can't comment his answer, so I posted my own )