Reputation: 53
I am new to c++ templates. I am writing a set of functions that can manipulate two different template classes. One needs to always be passed by value, the other must be passed by reference because it represents a huge amount of data.
Here is a simplified example. If the arg is tagged a ref type, I want the function signature to be defined as taking it by const ref.
template<bool B, typename, typename T2>
struct if_ {};
template<typename T1, typename T2>
struct if_<true, T1, T2> {
typedef T1 type;
};
template<typename T1, typename T2>
struct if_<false, T1, T2> {
typedef T2 type;
};
struct ByvalTypeTag {};
template<typename T>
class Byval : public ByvalTypeTag
{
T somedata;
};
struct ByrefTypeTag {};
template<typename T>
class Byref : public ByrefTypeTag
{
T somedata;
};
template<typename T>
void myfunc(typename if_<std::is_base_of<ByrefTypeTag, T>::value, const T&, T>::type arg)
{
}
int _tmain(int argc, _TCHAR* argv[])
{
Byref<int> arg;
myfunc( arg );
return 0;
}
The error I get is:
error C2783: 'void myfunc(if_::value,const T&,T>::type)' : could not deduce template argument for 'T'
Maybe this is the wrong way of going about it. If possible I am trying to cut down on the number of relatively duplicate templates I am writing for the same function.
Upvotes: 0
Views: 226
Reputation: 63775
You can forward the parameter with this implementation.
template<typename T>
void myfunc_impl(T arg)
{
// Do the work here.
}
template<typename T>
void myfunc(const T &arg, typename std::enable_if<std::is_base_of<ByrefTypeTag, T>::value>::type* = 0)
{
myfunc_impl<const T&>( arg ); // Pass a const ref
}
template<typename T>
void myfunc(const T &arg, typename std::enable_if<std::is_base_of<ByvalTypeTag, T>::value>::type* = 0)
{
myfunc_impl<T>( arg ); // Pass a copy
}
Upvotes: 0
Reputation: 126452
You are trying to deduce type T
from a non-deduced context.
The presence of the double colon in the parameter's dependent type usually gives you hint that you won't be able to deduce the type of that parameter (unless you have other deduced contexts in the same function call that help, but here you have just one argument).
From Paragraph 14.8.2.5/5 of the C++11 Standard:
The non-deduced contexts are:
— The nested-name-specifier of a type that was specified using a qualified-id.
[...]
If you need a concrete example, this Q&A on StackOverflow provides a pretty good one. In this case, you could provide the type argument explicitly:
myfunc<Byref<int>>(arg);
Alternatively, you can choose one of the two workarounds proposed in this second Q&A.
Upvotes: 1
Reputation: 40859
Yeah, compiler cannot deduce the type. You'll need to provide it with T yourself:
myfunc<ByRef<int>>(arg);
Alternatively you can use the more usual tag-dispatching system:
class byref
{
typedef byref_tag tag;
...
};
template < typename T >
void fun(T const& t, byref_tag) { ... }
template < typename T >
void fun(T t, byval_tag) { ... }
template < typename T >
void fun(T const& t)
{
typedef typename T::tag tag;
fun(t,tag());
}
Yet another alternative would involve a wrapper function and class template. Either way though the outer function has to be by ref.
Upvotes: 1