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, "!");
}
Related
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.
I've written some template-meta nonsense to detect if class methods exists.
The template struct has_subscript is specialized so that the second template parameter is void if the first template parameter has a subscript operator. If the subscript operator is found, the specialization is used, otherwise SFINAE defaults to the non-specialized version.
I have the code working for a simple struct foo (it's templated just to better match std::vector), but it unexpectedly fails with std::vector.
demo link https://godbolt.org/z/5-QzAp
#include <type_traits>
#include <iostream>
#include <vector>
using namespace std;
template <typename>
struct void_wrap
{ using type = void; };
template <typename T, typename = void>
struct has_subscript
{
static constexpr bool value = false;
};
template <typename T>
struct has_subscript <T, typename void_wrap<typename result_of<decltype(&T::operator[])(T,int)>::type>::type >
{
static constexpr bool value = true;
};
template <typename T>
struct foo
{
double operator[](size_t x){return 0.0;}
};
int main()
{
cout << has_subscript<foo<int>>::value;
cout << has_subscript<vector<int>>::value;
}
It has to do with how you are attempting to deduce the operator[], it works for foo but not for std::vector because it is overloaded.
The expression typename result_of<decltype(&T::operator[])(T,int)>::type cannot be used since &T::operator[] is ambiguous.
If you use decltype(std::declval<T&>()[int()]), then it works as expected (see here).
You can use std::is_detected from the library fundamentals TS v2.
#include <type_traits>
#include <experimental/type_traits>
#include <vector>
template<typename T>
using bracket_op_t = decltype( std::declval<T&>()[0] );
template<typename T>
constexpr bool has_bracket_op = std::experimental::is_detected<bracket_op_t, T>::value;
int main()
{
// static_assert(has_bracket_op<int>, ""); // fails to compile
static_assert(has_bracket_op<std::vector<int>>, "");
}
LIVE DEMO
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?
Now that my previous question has a solution, more questions arise.
I want to use the wrap_into_container meta-function with boost::mpl::transform, e.g.:
#include <vector>
#include <list>
#include <boost/fusion/include/vector.hpp>
#include <boost/fusion/mpl.hpp>
#include <boost/mpl/transform.hpp>
namespace container
{
template <typename T> struct vector { typedef std::vector<T> type; };
template <typename T> struct list { typedef std::list<T> type; };
}
template<typename T, template <typename> class Container>
struct wrap_into_container
{
typedef typename Container<T>::type type;
};
int main()
{
namespace fusion = boost::fusion;
namespace mpl = boost::mpl;
typedef fusion::vector<int, float, int> vec_type;
typedef mpl::transform< vec_type, wrap_into_container<mpl::_1, container::vector> >::type wrapped_vec_type;
wrapped_vec_type w;
return w.size();
}
Link to coliru
But it seems like I cannot pass a template template parameter into mpl::transform ...
How can I solve this? Please provide a C++03 solution, since I cannot use C++11.
In boost::mpl, higher order functions are written by passing a fixed type with an internal apply template member (known as a metafunction class), rather than through the use of template-template parameters. Live Example.
#include <vector>
#include <list>
#include <boost/fusion/include/vector.hpp>
#include <boost/fusion/mpl.hpp>
#include <boost/mpl/transform.hpp>
#include <iostream>
namespace container
{
struct vector {
template<typename T> struct apply {
typedef std::vector<T> type;
};
};
struct list {
template <typename T> struct apply {
typedef std::list<T> type;
};
};
}
template<typename T, typename ContainerMaker>
struct wrap_into_container
{
typedef typename ContainerMaker::template apply<T>::type type;
};
int main()
{
namespace fusion = boost::fusion;
namespace mpl = boost::mpl;
typedef fusion::vector<int, float, int> vec_type;
typedef mpl::transform<
vec_type,
wrap_into_container<mpl::_1, container::vector>
>::type wrapped_vec_type;
wrapped_vec_type w;
std::cout << size(w) << "\n";
return size(w);
}
I don't know boost::mpl, so I can only speculate from what I've seen in the documentation.
I think what you need is
template<template <typename> class Container>
struct wrap_into_container
{
template<typename T>
struct map
{
typedef typename Container<T>::type type;
};
};
Followed by
typedef wrap_into_container<container::vector>::template map<mpl::_1> fun;
typedef transform<vec_type, fun>::type wrapped_vec_type;
In this case, fun is a class of the form C<mpl::_1> where C is a class template, and whose ::type is std::vector<mpl::_1>. I think this is what mpl::transform expects for its type map.
My only test is with my own version of transform, which works with template template arguments instead of placeholders for the type map. Check live example, where transform is defined using C++11 but the remaining part is C++03. In this example, I am only using
wrap_into_container<container::vector>::template map
as a template template argument to my transform, without the placeholder <mpl::_1>.
I hope this helps.
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.