Template function in template class - c++

Related to this
Can't get the following to compile and I don't really understand why.
Codebolt Code
Snippet here
#include <vector>
#include <string>
template<typename T>
class A
{
using func_type = bool(int const&);
template<func_type U, func_type X>
[[using gnu:cold]]void example(std::vector<std::string>&&);
};
template <typename T>
template <typename A<T>::func_type U, typename A<T>::func_type X>
void A<T>::example(std::vector<std::string>&&)
{
}
Thank you

If you don't want to use the func_type anywhere outside of your class. Then you should change it to
using func_type = bool(*)(int const&);
Remember that the syntax is similar to emplying typedef for function pointers.

Related

How to forward declare an aliased template in c++

I have the following aliased template:
#include <vector>
template <typename T>
using MyVector = std::vector <T>;
How can i forward declare MyVector?
template <typename T>
class MyVector;
does not work for me.
You might be able to get away with making it a type, which you will be able to forward-declare:
template <typename T>
struct MyVector: std::vector<T> {};
You cannot forward declare an using declaration.
Anyway, you can declare forward a sort of traits as it follows:
#include <type_traits>
#include <vector>
template<typename>
struct MyStuff;
template<typename T>
auto f() { return typename MyStuff<T>::MyVector{}; }
template<typename T>
struct MyStuff {
using MyVector = std::vector<T>;
};
int main() {
static_assert(std::is_same<decltype(f<int>()), std::vector<int>>::value, "!");
}

How to specialize template on arbitrary dependent type

Say, I have some template which specialized for several types, TypeMathcer, which has type member.
#include <memory>
#include <vector>
template <typename T>
struct TypeMatcher;
template <typename T>
struct TypeMatcher<T *>
{
// making some type from T
typedef std::shared_ptr<T> type;
};
template <typename T>
struct TypeMatcher<T&>
{
// making other type from T
typedef std::vector<T> type;
};
Now, I want to create another template and specialize it for types I get from TypeMatcher. If I do it straightforward, like this
template <typename T>
struct MyNeedfullTemplate;
template <typename T>
struct MyNeedfullTemplate<typename TypeMatcher<T>::type>
{
};
I get compiler error: template parameters not deducible in partial specialization.
Same error if use using syntax
template <typename T>
using type_matcher_t = typename TypeMatcher<T>::type;
template <typename T>
struct MyNeedfullTemplate;
template <typename T>
struct MyNeedfullTemplate<type_matcher_t<T> >
{
};
I read answer to question partial specialization for iterator type of a specified container type that is very similar to my question, but still not sure if existing of one counter-example makes all question senseless. Also now we have brand-new c++14 and c++17 standards which could change situation. So what if I ensure the specializations is unique and exists, will than any possibility to make parameters deducible?
This is impossible, on principle, and no fancy C++9999 can change that.
What you're asking the compiler to do:
There's a use such as MyNeedfulTemplate<int> in the code. The compiler needs a definition of MyNeedfulTemplate<U> for U = int. You've tried to provide a partial specialisation of the form
template <typename T>
struct MyNeedfullTemplate<typename TypeMatcher<T>::type>
To see whether this specialisation applies or not, the compiler would have to inspect TypeMatcher<T> for all possible Ts and find if any one of them has a nested typedef type that aliases int. This cannot happen, as the set of "all possible Ts" is infinite. OK, TypeMatcher<int> doesn't have such a type, and neither does TypeMatcher<int*>, nor TypeMatcher<int**>, nor TypeMatcher<int***>. But what if TypeMatcher<int****> does? Better keep trying...
Also remember that partial and complete specialisation exists, meaning that TypeMatcher itself could be specialised.
In short, there is no way to link an int to a TypeMatcher<X>::type if all you have is the int and not the X.
You should be able to achieve something similar by re-structuring (inverting) TypeMatcher a bit:
template <class T>
struct TypeMatcher2
{
static constexpr specialised = false;
};
template <class T>
struct TypeMatcher2<std::shared_ptr<T>>
{
static constexpr specialised = true;
using OldType = T*;
};
template <class T>
struct TypeMatcher2<std::vector<T>>
{
static constexpr specialised = true;
using OldType = T&;
}
template <class T, bool spec = TypeMatcher2<T>::specialised>
struct MyNeedfullTemplate
{
// generic version
};
template <class T>
struct MyNeedfullTemplate<T, true>
{
using OriginalT = typename TypeMatcher2<T>::OldType;
// specialised version
};
I think what you're trying to do is this:
#include <iostream>
#include <memory>
#include <vector>
#include <utility>
template <typename T>
struct TypeMatcher;
template <typename T>
struct TypeMatcher<T *>
{
// making some type from T
typedef std::shared_ptr<T> type;
};
template <typename T>
struct TypeMatcher<T&>
{
// making other type from T
typedef std::vector<T> type;
};
template <typename T, typename = void>
struct MyNeedfullTemplate;
template <typename T>
struct MyNeedfullTemplate<TypeMatcher<T>, std::enable_if_t<std::is_same<typename TypeMatcher<T>::type, std::vector<std::remove_reference_t<T>>>::value>>
{
static void report() { std::cout << "hello" << std::endl; }
};
int main()
{
using matcher_type = TypeMatcher<int&>;
using full_type = MyNeedfullTemplate<matcher_type>;
full_type::report();
return 0;
}
Do I understand the question correctly?

Specializing std::hash for derived classes works in gcc, not clang

I am trying to specialize std::hash for derved classes. The best approach so far is based on this answer:
#include <type_traits>
#include <functional>
#include <unordered_set>
namespace foo
{
template<class T, class E>
using first = T;
struct hashable {};
struct bar : public hashable {};
}
namespace std
{
template <typename T>
struct hash<foo::first<T, std::enable_if_t<std::is_base_of<foo::hashable, T>::value>>>
{
size_t operator()(const T& x) const { return 13; }
};
}
int main() {
std::unordered_set<foo::bar> baz;
return 0;
}
This compiles with g++ 5.2.0 with no warnings (-Wall -pedantic), but with clang++ 3.7.0 it results in the following error:
first.cpp:17:12: error: class template partial specialization does not specialize any template argument; to define the primary template, remove the template argument list
struct hash<foo::first<T, std::enable_if_t<std::is_base_of<foo::hashable, T>::value>>>
^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Is this a compiler error or an error in the code?
This question, proposes a SFINAE solution that technically works with both my gcc and clang versions. However, because it only disabled the operator, not the class, It starts to yield very confusing error messages when one tries to hash any non-hashable class:
template <typename T>
struct hash
{
typename std::enable_if_t<std::is_base_of<foo::hashable, T>::value, std::size_t>
operator()(const T& x) const { return 13; }
};
...
struct fail {};
std::unordered_set<fail> bay;
...
type_traits:2388:44: error: no type named 'type' in 'std::enable_if<false, unsigned long>';
'enable_if' cannot be used to disable this declaration
I would like to not consider the macro solution. I have further tried the following approaches:
template <typename T>
struct hash<std::enable_if_t<std::is_base_of<foo::hashable, T>::value, T>>
Both compiler complain that they cannot deduce the type, which I find rather irritating because I don't see much of a difference towards the first solution.
My first attempt was the usual common pattern for enable_if:
template <typename T,
typename DUMMY = std::enable_if_t<std::is_base_of<foo::hashable, T>::value>>
struct hash<T>
Which fails with default template argument in a class template partial specialization.
Is there a clean template metaprogramming way to acchieve this in C++14?
first a little rant:
the design of std::hash is awful. Partial specialisations are not allowed. the committee should have simply copied the boost implementation in full.
(rant over)
I think one elegant solution is to approach it from a different angle:
#include <type_traits>
#include <functional>
#include <unordered_set>
namespace foo
{
template<class T, class E>
using first = T;
struct hashable {};
struct bar : public hashable {};
template<class T, typename = void>
struct hashable_hasher;
template<class T>
struct hashable_hasher<T, std::enable_if_t<std::is_base_of<hashable, T>::value>>
{
size_t operator()(const T& x) const { return 13; }
};
template<class T, typename = void>
struct choose_hash {
using type = std::hash<T>;
};
template<class T>
struct choose_hash<T, std::enable_if_t<std::is_base_of<hashable, T>::value>> {
using type = hashable_hasher<T>;
};
template<class T>
using choose_hash_t = typename choose_hash<T>::type;
template<class T>
using choose_set_t = std::unordered_set<T, choose_hash_t<T>>;
}
int main() {
foo::choose_set_t<foo::bar> baz;
return 0;
}

friend of template method in template class, within a template class

The description can be quite mind boggling so I get straight to the example:
#include <iostream>
#include <typeinfo>
using namespace std;
template<typename T> class fr{
static void privatestuff(){
cout<<"private of "<<typeid(T).name()<<endl;
}
public:
template<typename TT> void callsomeone(){
fr<TT>::privatestuff();
}
//template<typename TT> friend void fr<TT>::callsomeone<T>();
//template<> template<typename TT> friend void fr<TT>::callsomeone<T>();
//template<typename TT> template<> friend void fr<TT>::callsomeone<T>();
//no other combinations... how to get it?
};
int main(){
fr<bool> obj;
obj.callsomeone<int>();
}
Basically, I want fr to be able to call fr<int>::privatestuff. But I'd like also to not expose more than what is needed, so make fr<int> friend of only fr<bool>::callsomeone<int>, not fr<bool>::callsomeone<char> or others.
I can count on c++11 if that's needed.
template<class x> template<class y> friend void fr<x>::callsomeone();
You shall not pass any template arguments to callsomeone, because you want to befriend a function template, and not a specialization of it (in other words, you want to befriend all specializations of it).

standard c++11 way to remove all pointers of a type

Is there a way to do this with some c++11 or at most a boost library?
#include <iostream>
#include <typeinfo>
using namespace std;
template <typename T> class remove_all_pointers{
public:
typedef T type;
};
template <typename T> class remove_all_pointers<T*>{
public:
typedef typename remove_all_pointers<T>::type type;
};
int main(){
//correctly prints 'i' on gcc
cout<<typeid(remove_all_pointers<int****>::type).name()<<endl;
}
That doesn't quite work for all pointer types. You need to account for different cv-qualifiers as well:
template <typename T> class remove_all_pointers<T* const>{
public:
typedef typename remove_all_pointers<T>::type type;
};
template <typename T> class remove_all_pointers<T* volatile>{
public:
typedef typename remove_all_pointers<T>::type type;
};
template <typename T> class remove_all_pointers<T* const volatile >{
public:
typedef typename remove_all_pointers<T>::type type;
};
Since C++17 you can create a readable, simple and cv-qualifier aware meta function.
Use it like:
int main()
{
remove_all_pointers_t<int* const* volatile* const volatile*> v = 42;
return 0;
}
C++20
#include <type_traits>
template<typename T>
struct remove_all_pointers : std::conditional_t<
std::is_pointer_v<T>,
remove_all_pointers<
std::remove_pointer_t<T>
>,
std::type_identity<T>
>
{};
template<typename T>
using remove_all_pointers_t = typename remove_all_pointers<T>::type;
C++17
In C++17 std::type_identity isn't available yet and std::identity isn't available anymore, hence you need to create your own 'identity' meta function:
#include <type_traits>
// your custom 'identity' meta function
template <typename T>
struct identity
{
using type = T;
};
template<typename T>
struct remove_all_pointers : std::conditional_t<
std::is_pointer_v<T>,
remove_all_pointers<
std::remove_pointer_t<T>
>,
identity<T>
>
{};
template<typename T>
using remove_all_pointers_t = typename remove_all_pointers<T>::type;
Neither Boost nor C++11 features such a trait template. But your code should work.