• Advertisement
Sign in to follow this  

[C++] SFINAE with MSVC 7.1

This topic is 4363 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Does SFINAE work properly with MSVC++ 7.1 (2003)? I'm having trouble getting boost::enable_if to work.

Share this post


Link to post
Share on other sites
Advertisement
Yes it does, remember enable_if takes an "integral constant" in the Boost.MPL sense (metadata), enable_if_c takes a plain old boolean constant. Show us how you are trying to use it.

Share this post


Link to post
Share on other sites
This is how I'm using it so far:


template < unsigned int v1, unsigned int v2>
struct is_equal { const static bool value = false; };

template < unsigned int v1 >
struct is_equal <v1,v1> { const static bool value = true; };

template < unsigned int rows, unsigned int columns>
class matrix
{
public:
typename boost::enable_if< is_equal<rows,columns> >::type setIdentity();
};




Now, it compiles fine when I create a matrix with rows == columns, but fails to compile when I try to instantiate one where rows != columns. I'm not attempting to call setIdentity() in either case.

Edit:
The error the compiler gives me is:
error C2039: 'type' : is not a member of 'boost::enable_if<Cond>'
with [ Cond=is_equal<2,3> ]



Just FYI, I'm trying to learn how to use SFINAE, I'm not trying to create a matrix class.

Share this post


Link to post
Share on other sites
Perhaps

class matrix
{
void setIdentity(typename boost::enable_if<is_equal<rows,columns>::type>::type* dummy = 0);
};

Share this post


Link to post
Share on other sites
SFINAE trick works with overloads of template functions, you're using it on a non-template function which isn't correct regardless of it being inside of a class template.

Share this post


Link to post
Share on other sites
Ah, ok. Thanks.

Is there a way to do what I'm trying to without partially specialising the class template? I'm trying to avoid partial specialisation because you have to repeat the entire class declaration.

Share this post


Link to post
Share on other sites
Quote:
Original post by Nitage
Is there a way to do what I'm trying to without partially specialising the class template? I'm trying to avoid partial specialisation because you have to repeat the entire class declaration.


There are a thew ways you could go about this, one of the top of my head would be:


#include <cstddef>
#include <boost/mpl/empty_base.hpp>
#include <boost/mpl/equal_to.hpp>
#include <boost/mpl/if.hpp>
#include <boost/mpl/empty_base.hpp>
#include <boost/mpl/size_t.hpp>

namespace mpl = boost::mpl;

template < typename Matrix >
struct matrix_impl {

typedef Matrix matrix_type;

void setIdentity() {
matrix_type& m = static_cast<matrix_type&>(*this);

// do identity operation
for(typename matrix_type::size_type i = 0; i < matrix_type::rows; ++i)
for(typename matrix_type::size_type j = 0; j < matrix_type::columns; ++j)
m[j] = ....;
}

};

template < std::size_t rows_, std::size_t columns_ >
struct matrix
: public mpl::if_<
mpl::equal_to< mpl::size_t<rows_>, mpl::size_t<columns_> >,
matrix_impl< matrix<rows_, columns_> >,
mpl::empty_base
>::type {

typedef float (&array_ref)[columns_];
typedef const float (&const_array_ref)[columns_];
typedef std::size_t size_type;

static const std::size_t rows = rows_;
static const std::size_t columns = columns_;

private:

float n[rows][columns];

public:

const_array_ref operator[](std::size_t n) const {
return n[n];
}

array_ref operator[](std::size_t n) {
return n[n];
}
};


Another way you could do it still using enable_if, you just make setIdentity a template function either a free-function or a static class member function.

Share this post


Link to post
Share on other sites
The perhaps easiest way would be to use a static_assert in your setIdentity member function, as Jonathan Turkanis did with the move_ptr library in the operator*, operator-> and operator[].

Share this post


Link to post
Share on other sites
Quote:
Original post by dalleboy
The perhaps easiest way would be to use a static_assert in your setIdentity member function.


I use static asserts and/or Concept checking pretty much all the time with template code:


#include <cstddef>
#include <boost/mpl/assert.hpp>
#include <boost/mpl/equal_to.hpp>
#include <boost/mpl/size_t.hpp>

namespace mpl = boost::mpl;

template < std::size_t M, std::size_t N >
struct matrix {

// .....
void setIdentity() {
BOOST_MPL_ASSERT((
mpl::equal_to< mpl::size_t<M>, mpl::size_t<N> >
));
// .... do set identity
}
};

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement