Template Specialization or whatever it's called

I've run into a bit of a template goof that I can't quite figure out.

So I have a function:
1
2
3
4
5
template<typename T>
T& getParam(std::string const &path)
{ 
    //...
}


and I want to specialize what that function does when T happens to be an std::vector<T>.

I attempted, this, but it's ambiguous with the original function.
1
2
template<typename T>
std::vector<T>& getParam(std::string const &path)


There's got to be a way to do it that I'm overlooking.
Any help is appreciated.
Last edited on
You cannot overload or specialize on the return type of a function.

You can cheat, though. :O)

It involves a temporary object that has a templated cast operator... I'm just climbing into bed now, but tomorrow I'll post details for you.
Use SFINAE.

For brevity, this assumes that the vector uses the default allocator:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#include <iostream>
#include <type_traits>
#include <vector>

template < typename T > struct is_vector : std::false_type {} ;
template < typename T > struct is_vector< std::vector<T> > : std::true_type {} ;

template < typename T > typename std::enable_if< is_vector<T>::value, T >::type
get_param( std::string path )
{
    std::cout << "get_param( " << path << " ) : overload for vector\n" ;
    // ...
    return T{} ;
}

template < typename T > typename std::enable_if< !is_vector<T>::value, T >::type
get_param( std::string path )
{
    std::cout << "get_param( " << path << " ) : overload for non-vector\n" ;
    // ...
    return T{} ;
}

int main()
{
    auto v = get_param< std::vector<int> >( "hello vector " ) ;
    auto i = get_param<int>( "hello non-vector" ) ;
    v.push_back(i) ;
}

http://coliru.stacked-crooked.com/a/67ba7e27d9d1db6e
Thanks JLBorges.
SFINAE is the conceptual area I lack in right now. Research time!
Okay so, I'm trying to implement this with boost. I (sort of) understand why all this works. But the compiler keeps spitting out an error when I try to implement the same thing with boosts's enable_if.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
template<typename T> struct is_int : boost::false_type {}
template<>           struct is_int<int> : boost::true_type {}   //this way, is_int<double>::value is false, 
                                                                //and is_int<int>::value is true
                                                                
template<typename T> typename boost::enable_if<typename is_int<T>::value, T>::type
getParam(std::string const &path)
{
  cout << "getParam specialized for int return" << endl;
  return T();
}

int main()
{
    get_param<int>("int");
    return 0;
}


This worked with C++11 type_traits. Swapping to boost the compiler keeps spitting out this:
main.cpp:29:5: error: no matching function for call to 'get_param'
get_param<std::vector<int> >("int");
^~~~~~~~~~~~~~~~~~~~~~~~~~~~
main.cpp:20:1: note: candidate template ignored: substitution failure [with T =
std::__1::vector<int, std::__1::allocator<int> >]: typename specifier
refers to non-type member 'value' in 'is_vector<std::__1::vector<int,
std::__1::allocator<int> >, bool>'
get_param(string const &path)


and I have no idea what it means.
Last edited on
as the compiler said, "typename specifier refers to non-type member 'value".

You wrote typename is_int<T>::value which tells the compiled that 'value' is a nested type within is_int<T>, but it is, in fact, the name of a member object. Just remove the keyword "typename" in that expression (or in is_vector<T>::value, which is what the compiler diagnostic says it was trying to use)
Last edited on
closed account (o1vk4iN6)
typename boost::enable_if</*typename*/ is_int<T>::value, T>::type

You are using typename on something that is a variable not a type.
See, that's what I thought, but removing typename gives me this response:
error: template argument for template type parameter must be a
type; did you forget 'typename'?
template <typename T> typename boost::enable_if<is_int<T>::value, T>::type
^
enable_if.hpp:35:19: note: template parameter
is declared here
template <class Cond, class T = void>
^

Why would it tell me a template type parameter must be a type, then?

EDIT: Resolved.
Apparently boost::enable_if checks a member variable named "value" internally, which makes this valid:
boost::enable_if<is_int<T>, T>::type
Last edited on
Topic archived. No new replies allowed.