Re: Help with template function overloading
On 19 Sep., 20:08, "marco.guazz...@gmail.com"
<marco.guazz...@gmail.com> wrote:
I need to write a function, say "do_something", which differs in the
number and type of input (template) parameters.
Specifically, I'd like to call "do_something" in these ways:
* do_something(v) // 1 template argument
* do_something<1>(m) // 1 compile-time arg and 1 template argument
* do_something<tag>(m) // 2 template arguments
where "v" is a vector and "m" is a matrix (so they have different
types), and "tag" is a tag-like class.
At the end of this email there is a toy example which should make you
things more clear (... not so toy since I need to integrate this kind
of functions in Boost.uBLAS).
If I compile this code with GCC 4.4.4,
$ g++ -Wall -Wextra -ansi -pedantic -g -o do_something
do_something.cpp
I get this error:
--- [error] ---
do_something.cpp: In instantiation of ?vector_traits<row_major_tag>?:
do_something.cpp:101: instantiated from here
do_something.cpp:60: error: no type named ?value_type? in ?struct
row_major_tag?
--- [/error] ---
Could someone point me out where I am wrong and how to fix it?
The problem is, that during overload resolution the
compiler *may* instantiate even those function templates
that are not selected, see [temp.inst]/5:
"If the overload resolution process can determine the correct
function to call without instantiating a class template
definition, it is unspecified whether that instantiation
actually takes place."
In your particular example, the compiler attempts to
instantiate the overload
template <typename ExprT>
typename vector_traits<ExprT>::value_type
do_something(vector_expr<ExprT> const&);
for your last call. During this attempt,
the specialization vector_traits<row_major_tag>
is instantiated because that is the return type
of this function. By doing that the class
member declarations are supposed to be
instantiated which leads to the invalid type
declaration
typedef typename row_major_tag::value_type value_type;
This error does not happen in the immediate
context of the declaration of do_something,
so this won't be silently ignored.
Note that a similar situation was reported
in an earlier thread:
http://preview.tinyurl.com/2vqo4kj
You can sfinae-protect your function declaration
by adding a helper trait, see below:
--- [code] ---
#include <cstddef>
#include <iostream>
template <typename ExprT>
struct expr
{
typedef ExprT expr_type;
};
template <typename ExprT>
struct vector_expr: expr< vector_expr<ExprT> >
{
typedef ExprT expr_type;
expr_type const& operator()() const
{
return *static_cast<expr_type*>(this);
}
expr_type& operator()()
{
return *static_cast<expr_type*>(this);
}
};
template <typename ExprT>
struct matrix_expr: expr< matrix_expr<ExprT> >
{
typedef ExprT expr_type;
expr_type const& operator()() const
{
return *static_cast<expr_type*>(this);
}
expr_type& operator()()
{
return *static_cast<expr_type*>(this);
}
};
template <typename T>
struct vector: vector_expr< vector<T> >
{
typedef T value_type;
};
template <typename T>
struct matrix: matrix_expr< matrix<T> >
{
typedef T value_type;
};
struct row_major_tag {};
struct column_major_tag {};
template <typename V>
struct vector_traits
{
typedef typename V::value_type value_type;
};
Replace above vector_traits by the following
version:
template <typename T>
struct has_value_type {
template <typename> struct wrapper {};
template <typename U>
static char test(wrapper<typename U::value_type>*);
template <typename>
static char (&test(...))[2];
static const bool value = sizeof(test<T>(0)) == 1;
};
template <typename V, bool = has_value_type<V>::value>
struct vector_traits {};
template <typename V>
struct vector_traits<V, true>
{
typedef typename V::value_type value_type;
};
template <typename M>
struct matrix_traits
{
typedef typename M::value_type value_type;
};
A similar fix should be done for this guy.
HTH & Greetings from Bremen,
Daniel Kr?gler
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]