can someone explain why the compiler accepts only this code
template<typename L, size_t offset, typename enable_if< (offset<sizeof(L)), int >::type =0>
void a_function(){}
template<typename L, size_t offset, typename enable_if< (offset==sizeof(L)), int >::type =0>
void a_function(){}
but not this:
template<typename L, size_t offset, typename enable_if< (offset<sizeof(L)), int >::type =0>
class a_class{};
template<typename L, size_t offset, typename enable_if< (offset==sizeof(L)), int >::type =0>
class a_class{};
The compiler sees the second class template as a redefinition of the first.
You have to use specialization for classes. Typically, it is done with an extra parameter:
template <class P, class dummy = void>
class T;
template <class P>
class T<P, typename enable_if<something, void>::type> {
the real thing
};
Two class (or class template) declarations with the same name should always declare the same class or class template (or be a specialization, in which case it is still the same template).
You probably want to do something like this (ideone.com link):
#include <iostream>
template< typename PL, size_t pOffset, int pC = int( sizeof(PL) ) - int( pOffset ) >= 0 ? ( int( sizeof(PL) ) - int( pOffset ) == 0 ? 0 : 1 ) : -1 >
class TClass
{
};
template< typename PL, size_t pOffset >
class TClass< PL, pOffset, -1 >
{
public:
static int const sI = -1;
};
template< typename PL, size_t pOffset >
class TClass< PL, pOffset, 0 >
{
public:
static int const sI = 0;
};
template< typename PL, size_t pOffset >
class TClass< PL, pOffset, 1 >
{
public:
static int const sI = 1;
};
int main(void )
{
TClass< char, 0 > lC0;
TClass< char, 1 > lC1;
TClass< char, 2 > lC2;
std::cout << lC0.sI << " : " << lC1.sI << " : " << lC2.sI << std::endl;
return ( 0 );
}
Program output:
1 : 0 : -1
Related
#include <iostream>
#include <type_traits>
class CL
{
public:
CL(){}
CL( int ) = delete;
};
template < class T >
class Creator
{
public:
template< std::enable_if_t< std::is_constructible<T, int>::value, int > = 0 >
static T* Create( int arg ) // 1
{
return new T( arg );
}
template< std::enable_if_t< std::is_default_constructible<T>::value && !std::is_constructible<T, int>::value, int > = 0 >
static T* Create( int arg ) // 2
{
return new T();
}
};
int main()
{
Creator<CL>::Create( 2 );
}
Here I give error that the first Create function can't deduce template argument, but then I commented it, the second overload is works fine. Why SFINAE doesn't work on first overload?
Your method is not template, it is your class which is template. You had to change
template<typename U = T,
std::enable_if_t< std::is_constructible<U, int>::value, int > = 0 >
static T* Create( int arg ) // 1
{
return new T( arg );
}
template<typename U = T,
std::enable_if_t< std::is_default_constructible<U>::value
&& !std::is_constructible<U, int>::value, int > = 0 >
static T* Create( int arg ) // 2
{
return new T();
}
#include <iostream>
template< class T, unsigned S >
struct my_iterator;
template< class T >
struct my_iterator< T, 1 >
{
T* p;
};
template< class T, unsigned S >
struct my_iterator : my_iterator< T, S / 2 >
{
static_assert ((S & (S - 1)) == 0, "S must be a power of 2");
using my_iterator< T, S / 2 >::p;
unsigned burp() {return (*p) + S;}
};
int main()
{
int v = 10;
my_iterator< int, 8 > a;
a.p = &v;
std::cout << a.burp() << std::endl;
my_iterator< int, 4 >& b = a;
std::cout << b.burp() << std::endl;
my_iterator< int, 1 > c;
c.p = &v;
std::cout << c.burp() << std::endl; // error: no member named 'burp'
return 0;
}
This will fix the error:
template< class T >
struct my_iterator< T, 1 >
{
unsigned burp() {return (*p) + 1;}
T* p;
};
but in my real code I have many methods, not just burp, all dependent on S and p, that would all need to be implemented twice, once in the general class and once in the specialization. Is there any way to avoid the duplicate code? I saw this similar question:
Avoiding code duplication in a specialized template
but the answer will not work in my case because I'll end up with many copies of p, one at each level of the recursive hierarchy.
Another option, if you have a recursion stop value of 1 which you want to still use, you can just move the stop value to 0...
This way my_iterator<T,1> still has the default implementation.
template< class T, unsigned S >
struct my_iterator;
template< class T >
struct my_iterator< T, 0 >
{
T* p;
};
template< class T, unsigned S >
struct my_iterator : my_iterator< T, S / 2 >
{
static_assert ((S & (S - 1)) == 0, "S must be a power of 2");
using my_iterator< T, S / 2 >::p;
unsigned burp() {return (*p) + S;}
};
An other way is to move specific stuff in an other structure:
template <typename T> struct opt_ptr { T* p; };
// to be able to use std::conditional with non instantiated type.
template <typename T> struct identity { using type = T; };
template<typename T, unsigned S>
struct my_iterator :
std::conditional<S == 1,
identity<opt_ptr<T>>,
identity<my_iterator<T, S / 2>>>::type::type
{
static_assert ((S & (S - 1)) == 0, "S must be a power of 2");
using opt_ptr<T>::p; // Note that you may use this->p to avoid this line
unsigned burp() {return *p + S;}
// Other methods using S and p.
};
You could pass down S to the base template, and move the method there.
template< class T, unsigned S, unsigned N >
struct my_iterator;
template< class T, unsigned S >
struct my_iterator< T,S, 1 >
{
unsigned burp() {return (*p) + S;}
T* p;
};
template< class T, unsigned S, unsigned N = S >
struct my_iterator : my_iterator< T, S, N / 2 >
{
static_assert ((S & (S - 1)) == 0, "S must be a power of 2");
using my_iterator< T,S, N / 2 >::p;
};
I have a class template which I use to get the size of a variable:
template <class T>
class Size
{
unsigned int operator() (T) {return sizeof(T);}
};
This works fine but for strings I want to use strlen instead of sizeof:
template <>
class Size<char *>
{
unsigned int operator() (char *str) {return strlen(str);}
};
The problem is when I create an instance of size with const char * it goes to the unspecialized version. I was wondering if there is a way to capture both the const and non-const versions of char * in on template specialization? Thanks.
Use this technique:
#include <type_traits>
template< typename T, typename = void >
class Size
{
unsigned int operator() (T) {return sizeof(T);}
};
template< typename T >
class Size< T, typename std::enable_if<
std::is_same< T, char* >::value ||
std::is_same< T, const char* >::value
>::type >
{
unsigned int operator() ( T str ) { /* your code here */ }
};
EDIT: Example of how to define the methods outside of the class definition.
EDIT2: Added helper to avoid repeating the possibly long and complex condition.
EDIT3: Simplified helper.
#include <type_traits>
#include <iostream>
template< typename T >
struct my_condition
: std::enable_if< std::is_same< T, char* >::value ||
std::is_same< T, const char* >::value >
{};
template< typename T, typename = void >
struct Size
{
unsigned int operator() (T);
};
template< typename T >
struct Size< T, typename my_condition< T >::type >
{
unsigned int operator() (T);
};
template< typename T, typename Dummy >
unsigned int Size< T, Dummy >::operator() (T)
{
return 1;
}
template< typename T >
unsigned int Size< T, typename my_condition< T >::type >::operator() (T)
{
return 2;
}
int main()
{
std::cout << Size< int >()(0) << std::endl;
std::cout << Size< char* >()(0) << std::endl;
std::cout << Size< const char* >()(0) << std::endl;
}
which prints
1
2
2
And you should also be able to write, of course:
template <>
class Size<const char *>
{
unsigned int operator() (const char *str) {return strlen(str);}
};
template <>
class Size<char *> : public Size<const char *>
{ };
...and, should you need to:
template <size_t size>
class Size<char[size]> : public Size<const char *>
{ };
template <size_t size>
class Size<const char[size]> : public Size<const char *>
{ };
One way is to use a helper function in order to determine if the template type is a char * or a char const *. You can do this with a simple struct. Then you can use SFINAE to select the proper specialization of your Size struct.
#include <cstring>
#include <iostream>
#include <boost/utility/enable_if.hpp>
template<typename T>
struct is_cstring {
enum { value = false };
};
template<>
struct is_cstring<char *> {
enum { value = true };
};
template<>
struct is_cstring<char const *> {
enum { value = true };
};
template<typename T, typename = void>
struct Size;
template<typename T>
struct Size<T, typename boost::disable_if<is_cstring<T> >::type> {
unsigned int operator ()(T const &) const {
return sizeof(T);
}
};
template<typename T>
struct Size<T, typename boost::enable_if<is_cstring<T> >::type> {
unsigned int operator ()(T const &str) const {
return strlen(str);
}
};
int main() {
std::string blah = "afafasa";
char *x = "asdfsadsad";
std::cout << Size<int>()(4) << std::endl;
std::cout << Size<char const *>()("blahblah") << std::endl;
std::cout << Size<char *>()(x) << std::endl;
}
The printed result is:
4
8
10
I'm trying to build a template class Fod
template<typename S0 = aux::EmptyType, typename S1 = aux::EmptyType, typename S2 = aux::EmptyType, typename S3 = aux::EmptyType, typename S4 = aux::EmptyType, typename S5 = aux::EmptyType, typename S6 = aux::EmptyType, typename S7 = aux::EmptyType, typename S8 = aux::EmptyType, typename S9 = aux::EmptyType>
class Fod { ... };
which will contain an inner class At with a static const int value indicating the index of the template argument (0 for S0, 1 for S1 and so on). Shortly, it should satisfy the condition:
struct Type0 {}; struct Type1 {};
BOOST_STATIC_ASSERT( (Fod<Type0>::At<Type0>::value == 0) );
BOOST_STATIC_ASSERT( (Fod<Type0, Type1>::At<Type0>::value == 0) );
BOOST_STATIC_ASSERT( (Fod<Type0, Type1>::At<Type1>::value == 1) );
I've tried using boost::disable_if as follows:
template<class T, class Enable = void>
class At; // undefined
template<>
struct At<S0, typename boost::disable_if<boost::is_same<S0, aux::EmptyType> >::type > {
static const int value = 0;
};
template<>
struct At<S1, typename boost::disable_if<boost::is_same<S1, aux::EmptyType> >::type > {
static const int value = 1;
};
template<>
struct At<S2, typename boost::disable_if<boost::is_same<S2, aux::EmptyType> >::type > {
static const int value = 2;
};
template<>
struct At<S3, typename boost::disable_if<boost::is_same<S3, aux::EmptyType> >::type > {
static const int value = 3;
};
// and so on for S4...S9
but it results in error when I define specialization for S3 and both S2,S3 are of the same type aux::EmptyType (or: I define specialization for S2 and both S1,S2 are of the same type).
4>C:\phd\cpp\src\boost/dst/fod.hpp(144): error C2766: explicit specialization ; 'boost::dst::fod<S0>::At<boost::dst::aux::EmptyType,boost::mpl::s_item<T,Base>>' has already been defined
4> with
4> [
4> S0=Type0
4> ]
4> and
4> [
4> T=Type0,
4> Base=boost::mpl::set0<>::item_
4> ]
Any ideas how to solve the problem?
And if I wanted a method size_t at<S0>() to give 0, size_t at<S1>() to give 1...?
Please ask if you need more information.
There's an easier solution to this, assuming that boost::is_same::value returns 0 or 1 (if your bool uses different values, just write a small compile-time converter):
Replace your current At with
template <typename T>
struct At {
enum {
value =
boost::is_same<T, S0>::value) +
boost::is_same<T, S1>::value * 10 +
boost::is_same<T, S2>::value * 100
};
};
which evaluates to a decimal-bitmask, if you need a bigger range feel free to use other values.
I've managed to answer the second question (about a template function) partially thanks to this answer:
#include <boost/utility/enable_if.hpp>
template <typename T>
static int at(typename boost::enable_if_c< boost::is_same<T, S0>::value && !boost::is_same<T, aux::EmptyType>::value, T >::type = T())
{
return 0;
}
// and so on for each class template parameter S1,...,S9
I answered my first question as well. Actually, it was easier that I had thought:
// main general template (unused or throws a compilation error)
template<class T, class Enable = void >
struct At {};
template<typename T>
struct At<T, typename boost::enable_if< boost::is_same<T, S0> >::type >
{
static const int value = 0;
};
// and so on for each class template parameter S1,...,S9
compiling with GCC i get always false from the following code. I believe this is a compiler bug, but someone may know better.
#include <iostream>
template< class T >
class has_apply {
typedef char yes[1];
typedef char no[2];
template< class U, U u >
struct binder {};
template< class U, unsigned n >
static yes& test( U*,
binder< void (U::*) ( const double& ),
&U::template apply< n >
>* = 0
);
template< class U, unsigned n >
static no& test( ... );
public:
static const bool result =
( sizeof( yes ) == sizeof( test< T, 0u >( (T*)(0) ) ) );
};
class A {
public:
template< unsigned n >
void apply( const double& );
};
int main()
{
std::cout << std::boolalpha << has_apply< A >::result << '\n';
return( 0 );
}
I can't claim to understand why, but I was able to make your code work by not taking U* and by pulling the declaration of the binder type out:
template< class T >
class has_apply {
public:
typedef char yes[1];
typedef char no[2];
template< class U, U u >
struct binder {};
typedef binder< void (T::*)(const double&), &T::template apply<0u> > b;
template < typename V, unsigned n >
struct declare
{
typedef binder< void (V::*)(const double&), &V::template apply<n> > type;
};
template< typename U, unsigned n >
static yes& test( typename declare<U,n>::type * );
template< class U, unsigned n >
static no& test( ... );
static const bool result =
( sizeof( yes ) == sizeof( test< T, 0u >( 0 ) ) );
};
You can actually simplify this a bit by removing the unsigned parameter from the function and just sticking 0u in the typedef within 'declare'.
Again, I can't explain why this intermediate metafunction is necessary but it was required and the above works in MSVC++ 2010
Andy Venikov's answer over in [comp.lang.c++.moderated] (I'm only taking credit for great google-foo (he he, I cheated)):
http://groups.google.com/group/comp.lang.c++.moderated/msg/93017cf706e08c9e
Like Noah I don't know why. Unlike Noah I didn't find a workable solution, but investigating the thing I managed to crash the MingW g++ 4.4.1 compiler (that is, an Internal Compiler Error). This was simply by inconsistently referring to apply as template and non-template:
#include <iostream>
template< class T >
class has_apply {
template< class U, U u >
struct binder {};
template< class U >
static double test(
U*,
binder<
void (U::*) ( const double& ),
//&U::template apply< 0 >
&U::apply
>* = 0
);
public:
static binder<
void (T::*) ( const double& ),
&T::template apply< 0 >
>* dummy();
static const bool result = sizeof( test( (T*)(0), dummy() ) );
};
class A {
public:
// template< unsigned n >
void apply( const double& );
};
int main()
{
std::cout << std::boolalpha << has_apply< A >::result << '\n';
return( 0 );
}
Effect on g++:
C:\test> g++ -std=c++98 y.cpp
y.cpp: In instantiation of 'has_apply':
y.cpp:38: instantiated from here
y.cpp:24: internal compiler error: in instantiate_type, at cp/class.c:6303
Please submit a full bug report,
with preprocessed source if appropriate.
See for instructions.
C:\test> _
He he...
PS: I'd love to post this as a "comment", since it's not an "answer".
This is not an answer to why it doesn't work. However, researching through the web, I've found some examples and eventually got to the following code, which may be even more to the point then what I've been trying.
I was trying to detect an specific member function signature, but the code below goes beyond and detects whether a given call is possible, no matter what is the signature. Hope the comments will be helpful.
#include <iostream>
template< class T >
class has_apply {
class yes { char c; };
class no { yes c[2]; };
struct mixin {
void apply( void );
};
// Calling derived::apply is only non-ambiguous if
// T::apply does not exist, cf. 10.2.2.
template< class U> struct derived : public U, public mixin {};
// The following template will help on deduction based on this fact.
// If U is type void (mixin::*) (void) then the template can be
// instantiated with u = &derived< U >::apply if and only if T::apply
// does not exist.
template< class U, U u >
class binder {};
// Therefore, the following template function is only selected if there
// is no T::apply:
template< class U >
static no deduce( U, binder< void (mixin::*) (void), &derived< U >::apply >* = 0 );
// Selected otherwise.
static yes deduce( ... );
// Provides an T object:
static T T_obj( void );
public:
static const bool result = ( sizeof( yes ) == sizeof( deduce( T_obj() ) ) );
};
namespace aux {
// Class to represent the void type as a "true" type.
class void_type {};
// deduce() some lines below will give us the right answer based on
// the return type of T::apply<>, but if it is void we cannot use a
// call to T::apply as an argument to deduce. In fact, the only
// function in c++ that can take such an argument is operator,() with
// its default behaviour and if an overload is not well formed it
// falls back to default.
template< class T >
T& operator,( const T&, void_type ) {};
// Copies the constness of T into U. This will be required in order
// to not get false positives when no const member is defined.
template< class T, class U >
struct copy_constness {
typedef U result;
};
template< class T, class U >
struct copy_constness< const T, U > {
typedef const U result;
};
}
template< class T >
class has_correct_apply{
class yes { char c; };
class no { yes c[2]; };
// We assume has_apply< T >::result is true so the following class
// is well declared. It is declared in a way such that a call to
// derived::apply< n >() is always possible. This will be necessary
// later.
struct derived : public T {
using T::apply; // possible iff has_apply< T >::result == true
// This template function will be selected if the function call
// we wish is otherwise invalid.
template< unsigned n >
static no apply( ... );
};
// const_correct_derived will have the same constness than T.
typedef typename aux::copy_constness< T, derived >::result const_correct_derived;
// Provides a const correct derived object.
static const_correct_derived derived_obj( void );
// Only possible call was derived::apply: call is impossible for signature:
static no deduce( no );
// Since te returned value of it will most likely be
// ignored in our code (void must be always [almost, see next]
// ignored anyway), we return yes from this:
static yes deduce( ... );
// As we noticed, an overload of operator,() may make an exact match necessary.
// If we want this we could simply have used "no" instead of "yes" above and:
// static no deduce( aux::void_type );
public:
static const bool result = ( sizeof( yes ) == sizeof( deduce(
( derived_obj().template apply< 0u >( 0.0 ), aux::void_type() )
) ) );
// Note: Inteestingly enough, GCC does not detect an private subclass default
// constructor and so const_correct_derived() could be used instead of
// having a function derived_obj(), but I do not know if this behavoiur is
// standard or not.
};
struct C {
template< unsigned n >
int apply( double, unsigned m = 10 ) const;
private:
C();
};
struct D {
template< unsigned n >
int apply( const double& );
private:
D();
};
struct E : public C {
};
struct Without{};
#include "mp.h"
int main()
{
std::cout << has_apply< E >::result << '\n';
std::cout << has_correct_apply< const E >::result << '\n';
std::cout << has_correct_apply< const D >::result << '\n';
std::cout << has_correct_apply< D >::result << '\n';
// E e;
return( 0 );
}