I already asked two questions related to what I'm trying to do (one resolved, one of which I will close soon). I know that C++ template instantiation does not allow any implicit conversions (see for example this comment), but I would like to simulate it.
Suppose I have the following skeleton code:
template <class T>
struct Base_A{
virtual void interface_func() const = 0;
};
template <class T>
struct Derived_A : public Base_A<T>{
typedef T value_type;
void interface_func() const{}
};
template <class T>
struct Base_B{
virtual void interface_func() = 0; // note: non-const
};
template <class T>
struct Derived_B : public Base_B<T>{
typedef T value_type;
void interface_func(){}
};
template <class BType>
struct Adapter : public Base_A<typename BType::value_type>{
BType &ref_B;
Adapter(BType &inst_B):ref_B(B_inst){}
void interface_func() const{} // does stuff with ref_B to simulate an A
};
template <class Should_Always_Be_Base_A>
void f(const Should_Always_Be_Base_A &arg){
// Only Base_A can be passed in by const ref
// Passing in a Base_B by const ref would not work.
}
Derived_A<int> A;
Derived_B<int> B;
f(A); // passes in A by const ref
f(B); // I want to pass in Adapter<Derived_B<int> >(B)
I want the template parameter for function f to always be a derived class of Base_A or an Adapter. The answer to restricting the type of arg can be done, but the implicit conversion to an Adapter cannot. Is there any way to do this? The net result is I want to be able to call f as f(A) or f(B), and in both cases I need to know the actual derived type of A or B within f (f cannot just see a reference to the base class).
Aside:
Presently, I just have f(A) working, and f(B) actually calls an overload which performs the Adapter construction, but I have other functions which take N arguments, each of which can be A or B, so I would need 2^N overloads.
For the curious, this is in application to the matrix library I'm working on. Base_A represents the base matrix type, and Base_B represents the base matrix-view type. For operations which will modify a matrix argument, I need to pass in the matrix by non-const reference or a modifiable matrix-view by const-ref. The adapter is just a trivial matrix-to-view adapter. So for example, I currently have a function like
Scale(const MatrixViewBase<T> &Mview, const T &scale_factor){
// does the actual work
}
Scale(MatrixBase<T> &M, const T &scale_factor){
Scale(Adapter<MatrixBase<T> >(M), scale_factor);
}
It's tedious and error prone to make 2^N copies of all these functions just to create the needed overloads to handle both views and non-views. As is, this is not good enough since I want Scale to be able to know the full derived type of Mview, not just the base class, because I will potentially generate instances of types dependent on Mview.
Edit 1: Changed all B types to have non-const interface functions. This was the original intent, so apologies for any confusion.
Edit 2: Have this working code, still requires 2^N overloads, but I can live with it unless someone suggests how to deal with that.
#include <iostream>
template <class T>
struct ReadableMatrix{
typedef T value_type;
};
template <class T>
struct WritableMatrix{
typedef T value_type;
};
template <class T>
struct WritableMatrixView{
typedef T value_type;
};
template <class T>
struct Matrix : public WritableMatrix<T>{
typedef T value_type;
typedef ReadableMatrix<T> readable_matrix;
typedef WritableMatrix<T> writable_matrix;
};
template <class T>
struct MatrixView : public WritableMatrixView<T>{
typedef T value_type;
typedef ReadableMatrix<T> readable_matrix; // not really used; needs an adapter before using
typedef WritableMatrixView<T> writable_matrix;
};
template <class T, class R>
struct IsReadableMatrix{
};
template <class T, class R>
struct IsReadableMatrix<ReadableMatrix<T>, R>{
typedef R type;
};
template <class T, class R>
struct IsWritableMatrix{
};
template <class T, class R>
struct IsWritableMatrix<WritableMatrix<T>, R>{
typedef R type;
};
template <class T, class R>
struct IsWritableMatrixView{
};
template <class T, class R>
struct IsWritableMatrixView<WritableMatrixView<T>, R>{
typedef R type;
};
template <class TA, class TB>
typename IsReadableMatrix<typename TA::readable_matrix,
typename IsWritableMatrixView<typename TB::writable_matrix,
void
>::type>::type
Copy(const TA &A, const TB &B){
std::cout << "Here" << std::endl;
}
template <class TA, class TB>
typename IsReadableMatrix<typename TA::readable_matrix,
typename IsWritableMatrix<typename TB::writable_matrix,
void
>::type>::type
Copy(const TA &A, TB &B){
std::cout << "Here2" << std::endl;
}
int main(){
Matrix<int> M, M2;
MatrixView<int> V, V2;
Copy(M, M2);
Copy(V, V2);
Copy(M, V);
Copy(V, M);
}
Do you need you base classes to be templates? Can you inject even "more base" nontemplate class?
If yes, you can do something like that:
struct Base_A{
virtual void interface_func() const = 0;
};
template <class T>
struct Derived_A : public Base_A{
typedef T value_type;
void interface_func() const{}
};
struct Base_B{
virtual void interface_func() const = 0;
};
template <class T>
struct Derived_B : public Base_B{
typedef T value_type;
void interface_func() const{}
};
struct Adapter
{
const Base_A* pA;
const Base_B* pB;
Adapter(const Base_B &inst_B) : pB(&inst_B), pA(0){}
Adapter(const Base_A &inst_A) : pA(&inst_A), pB(0){}
void interface_func() const
{
if( 0 != pA )
pA->interface_func();
else if( 0 != pB )
pB->interface_func();
}
};
void f(const Adapter &arg)
{
arg.interface_func(); // will call proper interface_func
}
int main()
{
Derived_A<int> A;
Derived_B<int> B;
f(A);
f(B);
}
Try the following:
template <template <typename> View, typename T>
struct Adapter
{
// Leave empty to cause errors if used, or you could
// provide a generic adapter for View<typename T::value_type>
}
// Partial specialization for a given base.
template <typename T>
struct Adapter<MatrixView, T> : MatrixView<typename T::value_type>
{
const T& t;
Adapter (const T& t)
: t(t)
{}
void some_virtual()
{
// Do stuff
}
}
template <template <typename> View, typename T>
const View<T>& adapt (const View<T>& v)
{
return v;
}
template <template <typename> View, typename T>
View<T> adapt (const T& t)
{
return Adapter<View, T>(t);
}
template <typename T, typename U>
foo(const MatrixViewBase<T> &Mview, const MatrixViewBase<U> &Mview2);
template <typename T, typename U>
foo (const T& t, const U& u)
{
return foo(adapt<MatrixViewBase>(t), adapt<MatrixViewBase>(u));
}
I put const in everywhere I could; you don't have to use it in every situation if it's not appropriate. You can use specializations of Adapter for a given T to further tailor the behavior.
Interestingly enough, this is the first time I've ever recommended template template parameters.
I have not looked into the details of a templated solution, but while you are at it, you can check the boost preprocessor library to help you in defining the 2^N variations of the template. This won't be nice on compile time, but it will be better than manually creating the variations.
I had to do this a while ago and the easiest (to maintain) solution I came up with was to have only one class (Matrix) that knows if it owns it's own data or is a view of someone else's data. E.g.,
Matrix A(n,m); //Creates a new matrix of size (n,m)
Matrix B=View(A); //Creates a matrix that's a view into A
Matrix C=View(pData,n,m); //Creates a matrix thats a view of data in a pointer that someone else owns
Foo(A);
Foo(B);
Foo(C);
It makes writing the Matrix class a little more difficult, but then later anyone who uses a Matrix, just uses it as a matrix, they don't need to care if it's a view or not.
Edited to add:
Why not just let BLAS manage the transpose for you? In the end, any of the BLAS functions are just going to want a pointer to a contiguous chunk of memory. So as long as your Matrix class knows how to get to that memory you're good. If the Matrix class has it's own isTransposed flag inside then you can do something like this:
Matrix A(n,m);
Matrix B=TransposedView(pData,m,n);
Matrix C=A*B;
Matrix& operator*(const Matrix& lhs, const Matrix& rhs)
{
Matrix result(lhs.Rows(),rhs.Cols()); //or did i get that backwards :)
char TransL=lhs.IsTransposed()?'T':'N';
char TransR=rhs.IsTransposed()?'T':'N';
_dgemm(TransL, TransR, ..., lhs.Data(), ..., rhs.Data(), ..., result.Data());
return result
}
Related
Let's say I want to create a variadic interface with different overloads for the structs A,B,C:
struct A{};
struct B{};
struct C{};
template <typename ... Ts>
class Base;
template <typename T>
class Base<T>{
public:
virtual void visit(const T& t) const
{
// default implementation
}
};
template<typename T, typename ... Ts>
class Base<T, Ts...>: Base<T>, Base<Ts...>{
public:
using Base<T>::visit;
using Base<Ts...>::visit;
};
int main()
{
A a;
B b;
auto base = Base<A,B,C>{};
auto base2 = Base<A,C,B>{};
base.visit(a);
base2.visit(b);
}
Now funtionally Base<A,B,C> is identical to Base<A,C,B> but the compiler still generates the different combinations. Of course with more template parameters it gets worse.
I assume there is some meta programming magic which can cut this code bloat down.
One solution might be to define template<typename T, typename U> Base<T,U> in a way that it checks if Base<U,T> already exists. This could reduce at least some combinations and can probably be done by hand for triplets as well. But I am missing some meta programming magic and hoping for a more general approach.
Edit:
I would like to have the variadic Interface for a (simplified) use case like that:
class Implementation:public Base<A,B,C>
{
public:
void visit(const A& a) const
{
std::cout <<"Special implementation for type A";
}
void visit(const B& a) const
{
std::cout <<"Special implementation for type B";
}
// Fall back to all other types.
};
using BaseInterface = Base<A,B,C>;
void do_visit(const BaseInterface& v)
{
v.visit(A{});
v.visit(B{});
v.visit(C{});
}
int main()
{
std::unique_ptr<BaseInterface> v= std::make_unique<Implementation>();
do_visit(*v);
}
The reason why I want to do this is that there could be potentially a lot of types A,B,C,... and I want to avoid code duplication to define the overload for each type.
Base<A, B, C> instantiates Base<A>, Base<B, C>, Base<B>, Base<C>
and
Base<A, C, B> instantiates Base<A>, Base<C, B>, Base<B>, Base<C>
Whereas final nodes are needed, intermediate nodes increase the bloat.
You can mitigate that issue with:
template <typename T>
class BaseLeaf
{
public:
virtual ~BaseLeaf() = default;
virtual void visit(const T& t) const
{
// default implementation
}
};
template <typename... Ts>
class Base : public BaseLeaf<Ts>...
{
public:
using BaseLeaf<Ts>::visit...;
};
Demo
Base<A,B,C> and Base<A,C,B> are still different types.
To be able to have same type, they should alias to the same type, and for that, ordering Ts... should be done in a way or another.
Looks like the member function should be a template rather than the class.
struct A{};
struct B{};
struct C{};
class Foo {
public:
template<typename T>
void visit(const T& t) const
{
// default implementation
}
};
int main()
{
A a;
B b;
auto foo = Foo{};
foo.visit(a);
foo.visit(b);
}
https://godbolt.org/z/nTrYY6qcn
I'm not sure what is your aim, since there is not enough details. With current information I think this is best solution (there is a also a lambda which can address issue too).
It's necessary to enforce some sort of discipline on the order of template parameters. You can do this with a template variable and a few static_asserts:
#include <type_traits>
template <typename ... Ts>
class Base;
struct A
{
};
struct B
{
};
struct C
{
};
struct D
{
};
template <class T>
static constexpr int visit_sequence_v = -1;
template <>
constexpr int visit_sequence_v<A> = 0;
template <>
constexpr int visit_sequence_v<B> = 1;
template <>
constexpr int visit_sequence_v<C> = 2;
template <typename T>
class Base<T>{
public:
static_assert(visit_sequence_v<T> >= 0, "specialize visit_sequence_v for this type");
virtual void visit(const T& t) const
{
// do nothing by default
}
};
template<typename T1, typename T2>
class Base<T1, T2>: Base<T1>, Base<T2>
{
public:
static_assert(std::is_same_v<T1, T2> || visit_sequence_v<T1> < visit_sequence_v<T2>);
using Base<T1>::visit;
using Base<T2>::visit;
};
template<typename T1, typename T2, typename ... Ts>
class Base<T1, T2, Ts...>: Base<T1>, Base<T2, Ts...>
{
public:
static_assert(std::is_same_v<T1, T2> || visit_sequence_v<T1> < visit_sequence_v<T2>);
using Base<T1>::visit;
using Base<Ts...>::visit;
};
int main()
{
A a;
B b;
auto base = Base<A,B,C>{};
//auto base2 = Base<A,C,B>{}; // static_assert fails
//auto base3 = Base<A,B,C,D>{}; // forgot to specialize
base.visit(a);
}
Notice the point here is to cause a compilation failure if you get the order wrong. If someone has the chops to do a compile-time sort it may be possible to cobble up a traits class (or a template function that you can use decltype on the return type) that selects an implementation of Base in the correct order.
One alternative is to declare a full specialization of Base for every individual type that can be visited (supplying a "default implementation" for visit) and declare a static constexpr visit_sequence within each specialzation.
A problem inherent in your method is that in the case of multiple inheritance, visit can be ambiguous:
struct E: public A, public B
{
};
// 5 MiNuTES LATeR...
DescendantOfBase<A, B> a_b;
E e;
a_b.visit (e); // ambiguous
I want to have general class Vector of any dimensions with template type
template <typename T, unsigned D>
class Vector {
public:
// constructors, methods and so on
protected:
T data[D];
};
and specializations for 2, 3 and 4 dimensions
template <typename T, unsigned D>
class Vector<T, 3> {
public:
T getX() const { return data[0]; }
// ...
};
this code, of course, doesn't work. How should I do it? If it is possible. Or, in any cases, I should use inheritance?
template <typename T>
class Vector3 : public Vector<T, 3> {
public:
T getX() const { return data[0]; }
};
gcc prints pretty straightforward error for your code:
error: template parameters not deducible in partial specialization: D
In order to set a partial specialization you should remove parameter D:
template <typename T> // <=== No *unsigned D* here
class Vector<T, 3> {
public:
// implementation here
};
and then implement the specialization.
Of course you can partially specialise your template class in any way. The only syntactic error you made is, that you should list the template parameters which are actually parameters (and not constants).
#include <iostream>
template <typename T, unsigned D>
class Vector {
public:
// constructors, methods and so on
protected:
T data[D];
};
template <typename T>
class Vector<T, 3> {
public:
// the same constructors (or not?)
T getX() const { return data[0]; }
T data[3];
};
int main() {
Vector<int, 3> arr;
arr.data[0]=42;
std::cout << arr.getX();
return 0;
}
Note that the specialization Vector<T,3> no longer lists D.
You can do whatever you want within the specialization. It can have a completely different body.
I would like to define a class template that takes function template arguments that operate on an instance of the class being defining.
Is this or something analogous possible?
I know that I could define conversion constructors, but for reasons not clear from this simplified example I want to be able to alter the functionality of the class with out changing its definition or creating derived types.
I know that I could include function pointer members and use setters to fix their functionality, but I would prefer to fix the functionality of the class using a declarative typedef rather than programmatically.
template
< typename T
, MyClass<X> (to_X)(MyClass<T>)
, MyClass<T> (from_X)(MyClass<X>)
>
class MyClass {
T value;
MyClass(T v) : value(v) {}
// is it possible to use to_X and from_X template args
// to declare member functions ...
}
MyClass<int> to_int(MyClass<std::string> value ) {
// return result of conversion
}
MyClass<std::string> to_string(MyClass<int> value ) {
// return result of conversion
}
MyClass<std::string, to_string, to_int> foo1 =
MyClass<std::string, to_string, to_int>("5");
MyClass<int, to_int, to_string> * foo2 = foo1.to_int();
I suggest you to use a policy-classes approach: Your class template is parametrized with the two conversion policies
template<typename T,
typename FROM,
typename TO
>
class MyClass
{
FROM from_t_conversion;
TO to_t_conversion;
MyClass() = default;
template<typename U>
operator U() const
{
return from_t_conversion( *this );
}
template<typename U>
MyClass( const U& u ) : MyClass()
{
std::swap( *this , to_t_conversion( u ) );
}
};
The point of this design is the type (form) of a conversion policy: A conversion policy could be any callable entity with the expected signature: A function, a functor, a lambda, etc.
EDIT: Here is an example of converters:
struct float_to_int
{
MyClass<itn> operator()( const MyClass<float>& )
{
return MyClass<int>{};
}
};
//A more generic conversion function:
template<typename T>
struct generic_to_converter
{
template<typename U , typename X = T>
MyClass<X> operator()( const MyCLass<U>& )
{
return /* something /*
}
};
Maybe don't overthink this and keep it simple:
template <typename T, typename Converter>
class MyClass
{
T value;
Converter converter;
public:
explicit MyClass(T const & v, Converter const & c = Converter())
: value(v), converter(c)
{ }
template <typename U, typename C = Converter>
operator MyClass<U, C>() const
{
return converter.template convert<U, C>(*this);
}
};
Your converter needs to look like this:
struct ExampleConverter
{
template <typename U, typename C1, typename T, typename C2>
MyClass<U, C1> convert(MyClass<T, C2> const &) const;
};
With a little bit more effort, you could take advantage of base class layout optimizations (in the same way that standard library implementations usually take care of allocators and comparators).
You could also have some rebind mechanic to allow the converter to be itself a template.
template <typename T, typename Converter = StandardConverter<T>>
class MyClass
{
T value;
Converter converter;
public:
explicit MyClass(T const & v, Converter const & c = Converter())
: value(v), converter(c)
{ }
template <typename U,
typename C = typename Converter::template rebind<U>::type>
operator MyClass<U, C>() const
{
return converter.template convert<U, C>(*this);
}
};
template <typename T>
struct StandardConverter
{
template <typename U, typename C>
MyClass<U, C> convert(MyClass<T, StandardConverter<T>> const &) const;
template <typename U> struct rebind { using type = StandardConverter<U>; };
};
I'm writing a set of C++ parameterized classes and I'm interested in some of them behaving similarly to pointers. In particular, I want to be able to create an object with a constant template parameter from an object with a non-constant template parameter, but not the other way around. This sample code should clarify my intentions:
int main() {
myClass<int> mc_int;
myClass<const int> mc_const_int;
myClass<const int> mc1(mc_const_int); // This should compile.
myClass<int> mc2(mc_int); // This should compile.
myClass<const int> mc3(mc_int); // This should compile.
myClass<int> mc4(mc_const_int); // This should NOT compile.
}
I have been able to achieve this particular behavior by creating the next class hierarchy (simplified for readability):
template <typename T>
class Base {
// ...
protected:
template <typename U>
Base(const Base<U> &obj): _elem(obj._elem) {}
private:
T _elem;
friend class Base<const T>;
};
template <typename T>
class myClass: public Base<T> {
// ...
public:
template <typename U>
myClass(const myClass<U> &obj): Base<const U>(obj) {}
};
And it works as expected, but I'm not entirely satisfied with this design because I can only detect a non-constant template parameter from the constructor, but not from any other member function.
If I wanted, for example, to create a container class with an addAll() method, I would like to be able to do this:
int main() {
Container<int> c_int;
c_int.add(new int(1));
c_int.add(new int(2));
c_int.add(new int(3));
Container<const int> c_const_int;
c_const_int.addAll(c_int); // This should compile.
c_int.addAll(c_const_int); // This should NOT compile.
}
But I don't know how to achieve the previous behavior. Does anyone have ideas for an alternate design to achieve what I'm trying to do? Does anyone know of a link where this problem is discussed in more depth?
Thanks in advance.
One way to do this is via partial template specialisation. You should define the class for non-const types as you usually would:
template <typename T>
struct MyClass {
void f(T&);
};
Then define a specialisation
template <typename T>
struct MyClass<T const> {
void f(T&);
void f(T const&);
};
Unfortunately, this leads to code duplication, but it should allow you to do what you want. Naturally, you can have the functions take MyClass<T>& and MyClass<T const>&, too.
I'm kind of understand the question a bit. You probably can use template specialization.
template <typename T>
class container
{
public:
template<typename U>
void addAll(const container<U>& b ){}
private:
template<>
void addAll(const container<int>&b); //No implementation
};
container<int> b;
....
container<const int> a;
a.addAll(b) ; //Give a link error, I can't understand why vc2010 compile and run this line though
One possibility is using member function templates, enabling them so as to achieve the combinations you want.
#include <utility>
template <class T, class U>
struct const_convertible;
template <class T>
struct const_convertible<T, T>: std::true_type {};
template <class T>
struct const_convertible<T, const T>: std::true_type {};
template <class T>
struct const_convertible<const T, T>: std::false_type {};
template <class T>
class X
{
public:
X() {}
X(const X&) {} //copy constructor
//conversion constructor as needed
template <class U>
X(const X<U>&, typename std::enable_if<const_convertible<U, T>::value, void>::type* = 0)
{}
template <class U>
typename std::enable_if<const_convertible<U, T>::value, void>::type f(X<U>) {}
};
int main()
{
X<int> mut;
X<const int> con;
X<int> a(mut);
//X<int> b(con);
X<const int> c(mut);
X<const int> d(con);
mut.f(mut);
//mut.f(con);
con.f(mut);
con.f(con);
//X<double> doub;
//doub.f(mut);
}
I'm currently writing a template that operates differently based on the category of the input.
There are 3 cases I'm looking to add to my traits class.
A. The type has a typedef type_category, use that.
B. The type doesn't have the typedef, use the type regular_tag (most common case)
C. My specializations, std::list<T> uses the type special_tag for any T.
How would I manage this? It's simple to do either A. and C. or B. and C. but I'm not sure how to get all 3.
EDIT
A example might make it easier to understand.
class Foo
{
typedef foo_tag type_category;
}
class Bar;
my_traits<Foo>::type(); // makes a foo_tag
my_traits<Bar>::type(); // makes a regular_tag
my_traits<std::list<Baz>>::type(); // makes a special_tag because I want special list proce
ssing.
The scaffolding could look like this:
template <typename T>
struct MyTrait
{
typedef typename MyHelper<T, CheckForType<T>::value>::type tag;
};
template <typename T>
struct MyTrait<std::list<T>>
{
typedef special_tag tag;
};
We need the helper:
template <typename T, bool>
struct MyHelper
{
typedef regular_tag tag;
};
template <typename T>
struct MyHelper<T, true>
{
typedef typename T::type_category tag;
};
Now all we need is a type-trait to check for a member typedef:
template<typename T>
struct CheckForType
{
private:
typedef char yes;
typedef struct { char array[2]; } no;
template<typename C> static yes test(typename C::type_category*);
template<typename C> static no test(...);
public:
static const bool value = sizeof(test<T>(0)) == sizeof(yes);
};
Usage:
MyTrait<Foo>::tag
The code by Kerrek works, but the following code is shorter and more versatile:
template <typename T,typename DefaultType>
class MyTrait
{
template <typename C> static DefaultType test( ... );
template <typename C> static typename C::type_category test( typename C::type_category * );
public:
using type = decltype( test<T>(nullptr) );
};
The reason I say that Kerrek's code is not versatile is that it requires you to hard-code the type "special_tag" so your class MyTrait will always use the same default tag. The code that I provide would allow you to use the class MyTrait with different defaults. For instance, it might happen that somewhere in the code, you want the default to be a int if the type_category is not defined, but elsewhere, you want it to be a float.
Let's look at an example. Suppose we design a class which is meant to take a container class such as the standard library vector as a template parameter. In our class, we want to use the same size_type as the underlying container. However, it might happen that somebody gives us a container that does not have size_type defined (for instance, a valarray does not define size_type). In this case, let's pretend I want to use int as the default (you should probably use size_t like the other standard containers, but if I changed the code you wouldn't be able to tell that the code is actually working). For this scenario I changed the classname from "MyTrait" to "size_typeof", and I changed the "type_category" to "size_type" (since this is the thing I want to look for). Some code for this scenario along with an example main function to see the types of the determined variables are given below:
#include <iostream>
#include <vector>
#include <valarray>
#include <typeinfo>
template <typename T,typename DefaultType>
class size_typeof
{
template <typename C> static DefaultType test( ... );
template <typename C> static typename C::size_type test( typename C::size_type * );
public:
using type = decltype( test<T>(nullptr) );
};
template <typename ContainerType>
class Matrix {
private:
// Change int to size_t in real code.
using size_type = typename size_typeof<ContainerType,int>::type;
size_type Rows;
size_type Cols;
public:
Matrix( size_t rows, size_t cols ) : Rows(rows), Cols(cols) {}
size_type rows(){ return Rows; }
size_type cols(){ return Cols; }
};
int main()
{
// Give the matrices some nonzero dimensions
Matrix<std::vector<double>> vec(5,2);
Matrix<std::valarray<double>> val(4,3);
// vectors have a size_type, almost always defined as size_t.
// So this should return your compiler's code for size_t
// (on my computer, this is "m")
std::cout << typeid( vec.rows() ).name() << std::endl;
// valarrays do not have a size_type.
// So this should return your compiler's code for int
// (on my computer, this is "i")
// It should return this code, since we used int as the default
// size_type in the Matrix class
std::cout << typeid( val.rows() ).name() << std::endl;
return 0;
}
Ok. That's great. But suppose I really did want to use just a hard-coded default for the DefaultType, instead of having to specify the DefaultType as a template parameter. Guess what? Template parameter defaults. Just define size_typeof like:
template <typename T,typename DefaultType = int>
class size_typeof {
...
};
and you are good to go. No need to specify the default type "int" anymore. For instance, in our Matrix class, we could have used
using size_type = size_typeof<ContainerType>;
The end.
template<class T>
T::type_category getType(T t, typename T::type_category c=typename T::type_category())
{ return c;}
template<class T>
regular_tag getType(T t, ...)
{ return regular_tag();}
template<class T>
special_tag getType(std::list<T> t, typename std::list<T>::type_category c=typename std::list<T>::type_category())
{ return special_tag();}
int main() {
auto a = getType(int);
auto b = getType(std::iterator_traits<char*>);
auto c = getType(std::list<char>);
}
I'm not that great with SFINAE, so I doubt this even compiles, but something like this is the direction to look.