How is below code working to detect if the two classes are same? Specially I did not get the syntax second IsSame class. It does not look like the explicit initialization. Please let me know which link I should go through to understand this? I am following book 'C++ the complete reference' by Robbert Schildit.
template<typename A, typename B> struct IsSame {
static const bool same = false;
};
template<typename A> struct IsSame<A, A> {//have confusion here
static const bool same = true;
};
template<typename A, typename B> bool IsSameClass() {
return IsSame<A, B>::same;
}
int main(void)
{
cout << IsSameClass<vector<int>, vector<int>>();//returns 1
cout << IsSameClass<vector<int>, vector<float>>();//returns 0
}
The first definition of IsSame is a primary template. The second one is its partial specialization.
When you use IsSame within IsSameClass, if template arguments match the partial specialization (i.e., if both arguments represent the same type) then this partial specialization is instantiated and the function returns its same value which is true. Otherwise, the primary template is instantiated and function returns false.
Related
I've got a template c++ object as follows
template <typename T, Dimension D>
class Field : public std::vector<T>
{
// ... lot of stuff ...
T differentiate(const gridPoint<D>&, int) const;
};
This differentiate methode is computed differently depending of the Dimension D
enum Dimension : std::size_t { _2D = 2, _3D = 3 };
I could just put a switch inside the method's body bt I'd like to use the templates in order to help with clarity
I tried using std::enable_if like this:
template <typename T, Dimension D>
typename std::enable_if<D==_2D, T>::type
Field<T,D>::differentiate(const gridPoint<D>& pt, int extent) const
{
// ... lot of computation
}
template <typename T, Dimension D>
typename std::enable_if<D==_3D, T>::type
Field<T,D>::differentiate(const gridPoint<D>& pt, int extent) const
{
// ... even more computation
}
but the compiler tels me that my implementation doesn't match any prototypes
What did I do wrong ? I just can't figure out how i'm suppose to declare the method's code
You can probably save yourself a lot of hassle and unreadable code in the long run by writing distinct partial specializations of Field for the 2D and 3D case:
enum Dimension : std::size_t { _2D = 2, _3D = 3 };
template <Dimension D>
using gridPoint = std::array<int, D>;
template <typename T>
struct Field_base : std::vector<T> {
// Stuff common to both specializations goes here.
using std::vector<T>::vector;
};
template <typename, Dimension>
struct Field;
template <typename T>
struct Field<T, _2D> : Field_base<T>
{
using grid_point = gridPoint<_2D>;
using Field_base<T>::Field_base;
T differentiate(const grid_point&, int) const
{
std::cout << "2D differentiate called\n";
return {};
}
};
template <typename T>
struct Field<T, _3D> : Field_base<T>
{
using grid_point = gridPoint<_3D>;
using Field_base<T>::Field_base;
T differentiate(const grid_point&, int) const
{
std::cout << "3D differentiate called\n";
return {};
}
};
For SFINAE to work, I believe the function needs to be templated so that this becomes a choice of which function compiles during overload resolution, not which function compiles during class instantiation.
I modified this as follows and it "works" on this end:
#include <iostream>
#include <vector>
enum Dimension : std::size_t { _2D = 2, _3D = 3 };
template <Dimension D>
struct gridPoint
{
int d[D];
};
template <typename T, Dimension D>
struct Field : public std::vector<T>
{
template <Dimension D2>
typename std::enable_if<D== D2 && D==_2D, T>::type
differentiate(const gridPoint<D2>& pt, int extent) const
{
std::cout << "2D differentiate called" << std::endl;
return T(0.0);
}
template <Dimension D2>
typename std::enable_if<D==D2 && D==_3D, T>::type
differentiate(const gridPoint<D2>& pt, int extent) const
{
std::cout << "3D differentiate called" << std::endl;
return T(0.0);
}
};
int main() {
Field<double, _2D> foo;
gridPoint<_2D> point { 3, 4 };
foo.differentiate(point, 3);
gridPoint<_3D> p3 { 3, 4, 5 };
Field<double, _3D> bar;
bar.differentiate(p3, 8);
return 0;
}
I didn't sort out the template foo to get this to compile with the definition out-of-line.
The compiler error provoked by your attempted out-of-line SFINAE definitions
for T Field<T,Dimension>::differentiate(const gridPoint<D>&, int) const would be:
error: prototype for ‘typename std::enable_if<(D == _2D), T>::type Field<T, D>::differentiate(const gridPoint<D>&, int) const’ does not match any in class ‘Field<T, D>’
error: candidate is: T Field<T, D>::differentiate(const gridPoint<D>&, int) const
error: prototype for ‘typename std::enable_if<(D == _3D), T>::type Field<T, D>::differentiate(const gridPoint<D>&, int) const’ does not match any in class ‘Field<T, D>’
error: candidate is: T Field<T, D>::differentiate(const gridPoint<D>&, int) const
or words to that effect.
The compiler insists that any purported out-of-line definition of a member function
of Field<T,Dimension> has the same prototype as the declaration of
of some member function, and its diagnostics spell out that this requirement is
not satisfied for either of the purported out-of-line definitions.
It is no good protesting that if the compiler would just carry on and do the SFINAE,
it then would discover that the one surviving out-of-line definition matches a member function declaration. It can't do
the SFINAE until it attempts some instantiation of Field<D,Dimension>, and making sure that
any out-of-line template/class member definitions pair off with template/class member declarations comes earlier on its
to-do list than instantiating templates. Instantiation might never happen, but orphan
member definitions are always wrong.
So, both of those SFINAE-embellished prototypes would have to appear as member
function declarations.
But then, if the compiler is to tolerate both of these SFINAE-embellished member
function declarations, they must be template member functions (not merely
member functions of a class template) and their respective std::enable_if conditions
must depend upon a template parameter of the member function. Such are the SFINAE
rules.
Summing up, what you need to write to accomplish your out-of-line SFINAE definitions is
illustrated by the following program:
#include <iostream>
#include <vector>
enum Dimension : std::size_t { _2D = 2, _3D = 3 };
template<Dimension D>
struct gridPoint {}; // ...whatever
template <typename T, Dimension D>
class Field : public std::vector<T>
{
public:
template <Dimension Dim = D>
typename std::enable_if<Dim ==_2D, T>::type
differentiate(const gridPoint<Dim>&, int) const;
template <Dimension Dim = D>
typename std::enable_if<Dim ==_3D, T>::type
differentiate(const gridPoint<Dim>&, int) const;
};
template <typename T, Dimension D> template<Dimension Dim>
typename std::enable_if<Dim ==_2D, T>::type
Field<T,D>::differentiate(const gridPoint<Dim>& pt, int extent) const
{
std::cout << "_2D differentiate" << std::endl;
return T(); // ...whatever
}
template <typename T, Dimension D> template<Dimension Dim>
typename std::enable_if<Dim ==_3D, T>::type
Field<T,D>::differentiate(const gridPoint<Dim>& pt, int extent) const
{
std::cout << "_3D differentiate" << std::endl;
return T(); // ...whatever
}
int main()
{
Field<int,_2D> f_2d;
gridPoint<_2D> gp_2d;
f_2d.differentiate(gp_2d,2);
Field<float,_3D> f_3d;
gridPoint<_3D> gp_3d;
f_3d.differentiate(gp_3d,3);
f_3d.differentiate(gp_2d,2);
return 0;
}
In this not very pleasant light, you might possibly want to review the question of whether Dimension needs to be a template parameter of
Field, or whether it might just be a template parameter of member functions of Field. As I
don't know the complete implementation of the template, I can't say. Alternatively, you might reconsider your dislike of the
template base class + partial specialization approach suggested by #casey.
Presumably you would like the alternative definitions of differentiate out-of-line because they are big and you don't want them
sprawling in the body of the class template. In thorny cases like this a plodding but fairly failsafe way of extruding template/class member definitions to be out-of-line
is first to code the template/class with inline definitions and get a successful build; then copy-paste the inline definitions to their
out-of-line places, add the required template/class qualifications and delete default specifiers; then truncate the original in-line definitions to declarations;
then get a successful build again.
The output of that example program is:
_2D differentiate
_3D differentiate
_2D differentiate
The last line is emitted by the execution f_3d.differentiate(gp_2d,2), which draws attention to the fact that the selected implementation of differentiate
is determined by the Dimension of the gridPoint<Dimension>& argument that is passed to it and not by the Dimension of the
Field<T,Dimension> on which it is invoked. Thus we can call Field<T,_3D>::differentiate<_2D>. Since you said:
This differentiate methode is computed differently depending of the Dimension D
this on the face of it seems to be the behaviour you want, as the gridPoint<Dimension>
argument differentiates the implementations of differentiate according to the value of
Dimension. But this observation revives the question: Is there really a good reason for
Dimension to be a template parameter of Field, and not just a template parameter of differentiate?
If there is really a good reason, then you want it to be impossible to call Field<T,_3D>::differentiate<_2D>
or Field<T,_2D>::differentiate<_3D>. You can achieve that by replacing all occurrences of <Dim> with
<D> in the program, though the SFINAE implementation then looks even more laboured.
I went into trouble understanding the following codes:
#include <iostream>
using namespace std;
template <class PixType, bool B = PixType::is>
class Test {
public:
void print() {
cout << "PixType B=false" <<endl;
}
};
template <class PixType>
class Test<PixType,true> {
public:
void print() {
cout << "PixType B=true" <<endl;
}
};
class PT {
public:
static const bool is = false; // here is the magic
};
int main() {
Test<PT> t;
t.print();
}
I have 4 questions:
What's the difference between the first template test class(with <> right after template instead of the class name) and the second one(with <> after class name Test).
Why can two same classes(both are named Test) exist at the same time.
In fact, when the is in class PT is set to be true, the program will print out PixType B=true, otherwise PixType B=false, and I don't know the magic here.
I tried to change the second template Test class to be like:
template <class PixType, bool B= true>
class Test {
public:
void print() {
cout << "PixType B=true" <<endl;
}
};
But the compiler will warn me of name conflict.
I am really new to these template stuff, and got really confused by these lines of codes. And I don't know how to search for this trick. In most articles about C++ templating, they just talk about some basic ideas and usages about template.
Any help will be greatly appreciated.
Point 1 What's the difference between the first template test class(with <> right after template instead of the class name) and the second one(with <> after class name Test).
Response The first one is the main class template definition. The second one is a specialization of the class template where the second parameter of the template is true.
If you didn't have the second one, the first one will be used regardless of whether the second parameter of the template is true or false.
Point 2 Why can two same classes(both are named Test) exist at the same time.
Response In your case, the second one is a specialization of the first one. When you use:
Test<int, true> a;
The compiler knows to use the specialization to generate code for Test<int, true>. When you use:
Test<int, false> b;
The compiler know to use the first one to generate code for Test<int, false>.
Point 3 In fact, when the is in class PT is set to be true, the program will print out PixType B=true, otherwise PixType B=false, and I don't know the magic here.
Response As I explained above, when the second parameter is true, the compiler uses the second class template. Otherwise, it uses the first class template. I hope there is no confusion about that any more.
Point 4 I tried to change the second template Test class to be like:
template <class PixType, bool B= true>
class Test {
public:
void print() {
cout << "PixType B=true" <<endl;
}
};
But the compiler will warn me of name conflict.
Response
Class templates can only be specialized, they cannot be overloaded.
template <typename A, typename B> class C1 {};
template <typename A> class C1 {};
The above is not supported by the language.
template <typename A, typename B> class C1 {};
template <typename A> class C1<A, A*> {};
The above is supported by the language. The second class template is a specialization of the first class template.
What you are trying to do is provide a default value for the second parameter but the name used to define the class template is same. The second one is a different class template not a specialization of the first class template.
I have a templated matrix class that I explicitly instantiate for various POD types and custom class types. Some of the member functions however don't make sense for a few of such custom types. For example:
Matrix<int> LoadFile(....); // This makes sense
Matrix<My_custom_class> LoadFile(...); //This doesn't make sense in the context of the custom class
Can I prevent the instantiation of the LoadFile function (which is a member function) for Matrix objects of select types? So far I have avoided the issue by making LoadFile a friend function and then explicitly controlling its instantiation. But I want to know if I can do this when LoadFile is a member function of Matrix.
The first question is whether you really need to control this. What happens if they call that member function on a matrix that stores My_custom_class? Can you provide support in your class (or the template) so that the member function will work?
If you really want to inhibit the use of those member functions for some particular type, then you can use specialization to block the particular instantiation:
template <typename T>
struct test {
void foo() {}
};
template <>
inline void test<int>::foo() = delete;
Or even just add static_asserts to the common implementation verifying the preconditions for what types is it allowed or disallowed?
template <typename T>
struct test {
void foo() {
static_assert(std::is_same<T,int>::value || std::is_same<T,double>::value,
"Only allowed for int and double");
// regular code
}
};
with std::enable_if, this is the best I can come up with
template< typename T >
struct Matrix {
template< typename T >
Matrix< typename std::enable_if<std::is_integral<T>::value, T>::type >
LoadFile()
{
return Matrix<T>();
}
};
Matrix<int> a;
Matrix<int> b = a.LoadFile<int>()
only type int compile while other don't.
Can I prevent the instantiation of the LoadFile function (which is a member function) for Matrix objects of select types?
Your best bet here would be to use a static_assert that would create a compiler error when you attempt to call the method in a version of the class instantiated with a blocked type. Using std::enable_if, and other methods that would selectively "disable" a method itself would require you to create partial or full specializations of the class with and without the methods in question in order to prevent compiler errors. For instance, AFAIK, you cannot do the following:
template <typename T>
struct test
{
static const bool value = false;
};
template<>
struct test<double>
{
static const bool value = true;
};
template<typename T>
struct example
{
void print() { cout << "Printing value from print()" << endl; }
typename enable_if<test<T>::value, T>::type another_print()
{
cout << "Printing value from another_print()" << endl;
return T();
}
};
If you attempted to instantiate an example<int>, etc., you would end up with a compiler error at the point of instantiation of the object type. You couldn't simply call example<int>::print() and be okay, and only run into a problem if you chose to call example<int>::another_print(). Specializations of example<T> could get you around the issue, but that can be a bit of a mess. As originally surmised, a static_assert would probably be the easiest case to handle, along with a nice message to the end-user explaining what went wrong.
Keep in mind that creating compiler errors is the goal, and it's a good one to have. If you blocked a method from being instantiated, and the end-user decided to invoke it, you'd end up with a compiler error either way. The version without the static_assert will leave a lot of head-scratching as the user of your class attempts to parse a probably very verbose compiler error message, where-as the static_assert method is direct and to the point.
If the selected set of types is known at compile time, and you are using c++11 with a compiler that supports type aliases, uniform initialization and constexpr (for example gcc 4.7) you can make your code a bit cleaner like this (from previous example above by yngum):
template <bool Cond, class T = void>
using enable_if_t = typename std::enable_if<Cond, T>::type;
template< typename T >
struct Matrix {
template< typename T >
//std::is_integral has constexpr operator value_type() in c++11. This will work thanks to uniform init + constexpr. With the alias, no more need for typename + ::type
Matrix<enable_if_t<std::is_integral<T>{}>>
LoadFile()
{
return Matrix<T>();
}
};
Matrix<int> a;
Matrix<int> b = a.LoadFile<int>();
Beware of compatibility of this code, though, because these features have been only recently supported and some compilers don't do yet. You can see more about c++11 compiler support here.
If you could use the TypeLists from the ( http://www.amazon.com/Modern-Design-Generic-Programming-Patterns/dp/0201704315 ) - Loki you could implement something like:
template<bool>
struct Static_Assert;
template<>
struct Static_Assert<true>{};
class B{};
template<typename T>
class A{
public:
A(){
Static_Assert< 0 == utils::HasType<T, TYPELIST_2(B,int) >::value >();
}
};
Then your HasType would be something like:
template<typename T, typename TList>
struct HasType{
enum { value = 0+HasType< T, typename TList::Tail >::value };
};
template<typename T>
struct HasType< T, NullType >{
enum { value = 0 };
};
template<typename T, typename U>
struct HasType< T, TypeList<T, U> >{
enum { value = 1 };
};
In the list you can add the classes which you would like prevent to be passed as the template parameters.
I'm trying to have a different template specialization for classes which have an inner class with a particular name present. I've taken a clue from here and tried the following:
#include <iostream>
template< typename T, typename Check = void > struct HasXYZ
{ static const bool value = false; };
template< typename T > struct HasXYZ< T, typename T::XYZ >
{ static const bool value = true; };
struct Foo
{
class XYZ {};
};
struct FooWithTypedef
{
typedef void XYZ;
};
int main()
{
// The following line prints 1, as expected
std::cout << HasXYZ< FooWithTypedef >::value << std::endl;
// The following line prints 0. Why?
std::cout << HasXYZ< Foo >::value << std::endl;
return 0;
}
As you can see, if I test for a typedef-defined type in FooWithTypedef, it works. However, it does not work if the type is a genuine inner class. It also only works when the typedef-ed type in FooWithTypedef matches the default value of the second argument in the initial template declaration (which is void in my example). Could one explain what is going on here? How does the specialization process work here?
Answer to the initial question
The template specialization you defined here:
template <typename T> struct HasXYZ <T,typename T::XYZ>
{ static const bool value = true; };
will take effect when somebody uses the data type HasXYZ<A,A::XYZ> for some data type A.
Note that, whatever A is, A::XYZ is a data type totally independent of A. Inner classes are data types in their own right. When you use A as the first template argument, there is absolutely no reason for the compiler to assume that you want to use something called A:XYZ as the second argument, even if an inner class of that name exists, and even if doing so would lead the compiler to a template specialization that matches the template arguments exactly. Template specializations are found based on the template arguments provided by the coder, not based on further possible template arguments.
Hence when you use HasXYZ<Foo>, it falls back to using the default template argument void for the second parameter.
Needless to say that if you were to use HasXYZ<Foo,Foo:XYZ> explicitly, you'd get the expected output. But that obviously is not what you intended.
I am afraid the only way to get what you need is std::enable_if (or something that works in a similar way).
Answer to the additional question (after update)
Consider the simplification below:
template <typename T, typename Check = void>
struct A
{ static const bool value = false; };
template <typename T>
struct A<T,void>
{ static const bool value = true; };
The primary definition specifies a default argument of void for the second template parameter. But the specialization (second definition above) defines what class A actually looks like if the second template parameter really is void.
What this means is that if you use, say, A<int> in your code, the default argument will be supplemented so you get A<int,void>, and then the compiler finds the most fitting template specialization, which is the second one above.
So, while default template arguments are defined as part of the primary template declaration, making use of them does not imply that the primary template definition is used. This is basically because default template arguments are part of the template declaration, not the template definition (*).
This why in your example, when typedef void XYZ is included in FooWithTypedef, the second template parameter defaults to void and then the most fitting specialization is found. This works even if in the template specialization the second argument is defined as T::XYZ instead of void. If these are the same at the time of evaluation, the template specialization will be selected (§14.4 "Type equivalence").
(*) I didn't find a statement in the Standard that actually says it so clearly. But there is §14.1/10, which describes the case where you have multiple declarations (but only one primary definition) of a template:
(§14.1/10) The set of default template-arguments available for use with a template declaration or definition is obtained by merging the default arguments from the definition (if in scope) and all declarations in scope in the same way default function arguments are (8.3.6). [ Example:
template<class T1, class T2 = int> class A;
template<class T1 = int, class T2> class A;
is equivalent to
template<class T1 = int, class T2 = int> class A;
].
This suggests that the mechanism behind default template arguments is independent of that used to identify the most fitting specialization of the template.
In addition, there are two existing SO posts that refer to this mechanism as well:
This reply to Template specialization to use default type if class member typedef does not exist
Default values of template parameters in the class template specializations
Here is another version that detects the presence of the inner class :
#include <iostream>
template< typename T >
struct HasXYZ
{
typedef char yes;
typedef struct{ char d[2]; } no;
template<typename T1>
static yes test( typename T1::XYZ * );
template<typename T1>
static no test(...);
static const bool value = ( sizeof( test<T>(0) ) == sizeof( yes ) );
};
struct Foo
{
class XYZ {};
};
struct Bar
{
class ABC {};
};
int main()
{
std::cout << std::boolalpha << HasXYZ< Foo >::value << std::endl;
std::cout << std::boolalpha << HasXYZ< Bar >::value << std::endl;
}
A::XYZ would need to void to have the partial specialization selected, which can never be the case for a class type. One way to make it work is using a fake dependant void typename:
template<class T>
struct void_{ typedef void type; };
template<class T, class = void>
struct has_XYZ{ static bool const value = false; };
template<class T>
struct has_XYZ<T, typename void_<typename T::XYZ>::type>{
static bool const value = true;
};
For an explanation on how this works, see this question.
This question already has answers here:
Why is it disallowed for partial specialization in a non-type argument to use nested template parameters
(2 answers)
Closed 6 years ago.
I tried to implement an SFINAE using bool (unlike popular void_ trick):
template<typename T, bool = true>
struct Resolve
{
static const bool value = false;
};
template<typename T>
struct Resolve<T, T::my_value>
{
static const bool value = true;
};
The goal is to specialize, the classes which have static const bool my_value = true; defined inside it. If they are defined false or not defined then don't specialize it. i.e.
struct B1 { // specialize Resolve for this case
static const bool my_value = true;
};
struct B2 { // don't specialize
static const bool my_value = false;
};
struct B3 {}; // don't specialize
When applying the above trick on B1 it gives the compilation error:
Resolve<B1>::value;
error: template argument ‘T::my_value’ involves template parameter(s)
I am aware that this can be achieved with alternate ways. However, I am interested in knowing, why it gives compiler error here and can it be solved in this code itself ?
Actually what you're doing is forbidden by section §14.5.4/9 which says,
A partially specialized non-type argument expression shall not involve a template parameter of the partial specialization except when the argument expression is a simple identifier.
The trick could be using a type for second template parameter as well, encapsulating the non-type value, as described below:
template<bool b> struct booltype {};
template<typename T, typename B = booltype<true> >
struct Resolve
{
static const bool value = false;
};
template<typename T>
struct Resolve<T, booltype<T::my_value> >
{
static const bool value = true;
};
Now it compile fines.