I'm trying to make a template function (in this case, in a class as a static method) and I can't seem to call the template specification I created. In other words, I expected the code to call the template specification I made and it doesn't.
class Atomic {
public:
template <typename T>
static T testAndSet(volatile T &t, T value)
{
ASSERT(false, "Unsupported type");
return T();
};
template <long>
static long testAndSet(volatile long &t, long value )
{
#if defined(_PC)
return InterlockedExchange(&t, value);
#else
return __sync_lock_test_and_set(&t, value);
#endif
};
};
Calling code:
volatile long counter = 0;
long newValue = 4;
Atomic::testAndSet( counter, newValue);
The callstack shows:
sample.exe!Atomic::testAndSet(volatile long & t=0, long value=4)
I also tried it this way but it didn't work.
template <typename T, typename TT>
static TT testAndSet(T &t, TT value) { ... }
template <volatile long, long>
static long testAndSet(volatile long &t, long value ) { ... }
or
template <typename T, typename TT>
static TT testAndSet(T t, TT value) { ... }
template <volatile long &, long>
static long testAndSet(volatile long &t, long value ) { ... }
Same thing... so now I have to try and understand what's happenning instead or brute forcing my way into it. Until then, I'll watch Lavavej's core c++ videos.. =)
You can explicitely specialize template functions, but that's not the standard method for functions. And you cannot do it like you do : what you've wrote is two template functions, one with a type parameter, the other with a long non-type parameter.
// This defines a template function parameted with a long
// vvvvvvvvvvvvvvv
template <long>
static long testAndSet(volatile long &t, long value )
You need to specify explicitely the template parameter on the call site for this overload to be considered, that's why it was never taken by the compiler.
You need overloading here, change the previous function with this one (explicit specialization is not needed):
// Not a template function
static long testAndSet(volatile long &t, long value)
Also, specializing a function template is done using the same syntax than for classes:
// Base case
template<typename T>
void function(T value);
// Explicit specialization (just an example)
template<>
void function<int>(int v, int a);
There are some differences between an explicit specialization and a simple overload, see this SO question for more details.
template <long>
static long testAndSet(volatile long &t, long value )
{
#if defined(_PC)
return InterlockedExchange(&t, value);
#else
return __sync_lock_test_and_set(&t, value);
#endif
};
That's not a specialization as you seem to think. It's an overload with a (unnamed) non-type template parameter. It'll never be selected during overload resolution for the call you made because you need to explicitly specify the parameter, like this for example: testAndSet<42>(counter, newValue);.
The syntax you want is:
template <> // <---
static long testAndSet<long>(volatile long &t, long value )
{ // ^^^^^^
//....
}
but at that point you could as well provide a normal overload.
You should always prefer overloading, because function template specializations can surprise you.
Related
I'm having trouble having an extra template parameter to my class template. I'm not sure if this is possible but I think it's clear what I'm trying to do:
struct NullableType { };
template <typename value_t>
struct ArrayMap
{
static inline constexpr bool bIsValueNullableType = std::is_base_of_v<NullableType, value_t>;
std::vector<value_t> arr;
void remove(const uint64 key)
{
if constexpr (bIsValueNullableType) arr[key].makeNull();
}
};
// In this version I want to take an integer type for the first argument and a null value as the second
template <typename integral_t, integral_t null_v >
struct ArrayMap
{
void remove(const uint64 key) { arr[key] = null_v;}
};
In the version taking an integer type and a null integer value I want to rewrite at least little code as possible, hopefully only removing and checking a key will require adding new functions.
As you haven't specified if you are limited to an old C++ standard I will propose a solution in C++20.
You can use template specialization. Your primary template will have to take two arguments (a type and a non type argument):
template <typename value_t = int, auto null_v = 0>
struct ArrayMap;
Then, a specialization for integral types can use the std::integral concept introduced in C++20. Otherwise you would have to use SFINAE (possibly an std::enable_if_t):
template <std::integral integral_t, integral_t null_v>
struct ArrayMap<integral_t, null_v>
{
std::vector<integral_t> arr;
void remove(const uint64_t key)
{
arr[key] = null_v;
}
};
Finally the specialization for non integral types can ignore the second argument:
template <typename value_t>
struct ArrayMap<value_t, 0>
{
static inline constexpr bool bIsValueNullableType = std::is_base_of_v<NullableType, value_t>;
std::vector<value_t> arr;
void remove(const uint64_t key)
{
if constexpr (bIsValueNullableType)
arr[key].makeNull();
}
};
As you can see there is a bit of code duplication. To deal with that, you could extract common functionality to a base class an inherit from it.
(godbolt)
I'm writing a C++ template that needs two params: typename T, and an arbitrary function that maps T to an unsigned int.
How can I declare and use a template that can do that? I'd like to keep it simple, so that any dumb function can be used.
UPDATE:
Here is an example of what I'd like to do:
template<typename T, function f> // f has signature: unsigned int f(T);
class SortedContainer {
...
}
And, in this file:
unsigned int weight(Package p) { return p.w; }
SortedContainer<Package, &weight> sc;
UPDATE upon writing code
Based on the answers, I tried writing code, but it won't compile. Or rather, the template will compile, but not the test which invokes it.
The template code looks like this:
template<typename T, typename f>
class C {
...f(T)...
...
The invocation code looks like:
struct S {
int operator()(const int n) {
return n; // Dummy test code
}
};
...C<int, S>&...
The error message is:
error: no matching function for call to 'S::S(const int&)'
note: candidates are:
note: S::S()
It seems like it's trying to use S's constructor for some reason, as opposed to using the operator() which I want it to do.
The purpose of the f parameter is that the SortedContainer needs to be able to position T by an integer value. T is not necessarily an integer or even Comparable, so the caller, when instantiating a SortedContainer, needs to pass not only type T, but a function f to transform T to an integer.
The common way of doing this is to accept a general type F for the function. This will allow any kind of function-like object, whether it is a function pointer or a class object with an overloaded operator(). So:
template<class T, class F>
class SortedContainer {
// ...
}
Compare with things like std::map which does exactly this.
The disadvantage of this is that you cannot control what the prototype of the function is. This may or may not be a problem. One way is just to use it as if it was T-to-unsigned int and rely on the fact that the type system will catch any errors at the point of use.
Another way would be to verify the constraint with some kind of type trait. An example:
static_assert(std::is_same<unsigned int,
typename std::result_of<F(T)>::type>::value,
"Function must be T-to-unsigned int");
Edit: I wrote a small example to convince myself i got the assert right, might as well post it. Here, using A will compile OK but B will fail the assertion.
#include <type_traits>
template<class T, class F>
class SortedContainer {
static_assert(std::is_same<unsigned int,
typename std::result_of<F(T)>::type>::value,
"Function must be T-to-unsigned int");
};
struct A {
unsigned int operator()(double) { return 0; }
};
struct B {
double operator()(double) { return 0; }
};
int main() {
SortedContainer<double, A> a;
SortedContainer<double, B> b;
}
Based on your other edit:
Note that the templated type F only captures the type of the function. You still need an object of this type - the actual function - to call. Again, compare with std::map which first is templated to take a comparator type, and then has a constructor that takes an object of this type. This is true even if you use a normal function - the type will be SortedContainer<T, unsigned int (*)(T)>, but you would somehow need to pass the actual function pointer into the container (probably through the constructor).
Something like this:
template<class T, class F>
class SortedContainer {
public:
SortedContainer(F f = F()): func(f) {}
void foo() {
// ...
func();
// ...
}
private:
F func;
};
struct A {
unsigned int operator()() { return 0; }
};
int main() {
A a;
SortedContainer<double, A> c(a);
c.foo();
}
IMO, you don't require a separate template argument for Function F.
template<typename T> // F not required!
class SortedContainer {
...
};
Choose a good name and use that function by overloading it for various cases. e.g. to_uint()
Since you want to map (i.e. relate) a type to an unsigned int (uint), use following function in global scope:
template<typename T>
uint to_uint (const T& t) {
return t.to_uint(); // Must have `uint to_uint() const` member, else error
}
// Overloads of `to_uint()` for PODs (if needed)
template<typename T> // For all kinds of pointers
uint to_uint (const T* const pT) {
if(pT == nullptr)
<error handling>;
return to_uint(*pT);
}
Scenario: For Sorted_Container<X>, whenever to_uint(x) is invoked, then:
If X is a class, then it must have uint to_uint() const method
Else if X is a POD, then you may have to overload to_uint() for that type
Else, the compiler will generate an error
It's as you said, pretty much:
template< typename T, unsigned int f(T) >
struct SortedContainer;
...
SortedContainer<Package, weight> sc;
if you actually wanted the argument to be a function pointer rather than a function,
template< typename T, unsigned int (*f)(T) >
and similarly if you want the argument to be a function reference.
(naturally, this will only work for dumb functions, not for function objects with an operator() operator of the right signature)
You may use C-style function pointers as #Hurkyl suggests, or std::function which probably can't be template parameters, but I think that idea is wrong.
C++ templates are duck-typed, so STL code in many places (std::unordered_map -> std::hash, std::sort -> std::less) relies on that. I think you should also apply this approach - just ask user to provide specialization for type T:
/* Universal implementation */
template<typename T>
unsigned int sorted_container_weight(T t) { return t; }
template<typename T>
class SortedContainer {
T t;
public:
unsigned int somefunc() {
return sorted_container_weight(t);
}
};
template<>
unsigned int sorted_container_weight<Package>(Package p) { return p.w; }
SortedContainer<Package> sc;
I have the following method in which I'm using boost::variant. I try to get the value, based on type T. If boost::get<T> fails I want to handle that in a special way if T is an int or unsigned int. Is there any way to know if T is an int or unsigned int?
I don't think I can use template specialization in this case, can I?
EDIT: Also, I don't yet have access to C++11 (soon I hope)
template < typename T, typename C, void (C::*setterFcn)(const T&) >
void binder( const Variant& value_var, C* c )
{
const T* typeData = boost::get<T>(&value_var);
if ( NULL == typeData )
{
// Need to check for int or unsigned int here somehow
}
(((C*) c)->*(setterFcn))(*typeData);
}
In C++11 you can use std::is_same and in C++03 you can do something like this:
template <typename T1, typename T2>
class is_same
{
public:
static bool const value = false;
};
template <typename T>
class is_same<T, T>
{
public:
static bool const value = true;
};
and use it exactly as C++11 standard version.
You could also use is_same() on boost or on C++11.
http://www.boost.org/doc/libs/1_51_0/libs/type_traits/doc/html/boost_typetraits/reference/is_same.html
http://en.cppreference.com/w/cpp/types/is_same
The easiest way is probably to just delegate to overloaded functions or function templates: You specify the general handling, possibly doing nothing, in one function and the specialized handling either in two separate functions (if the extra handling is trivial) or in an enable_ifed function with the condition checking for int or unsigned int.
I'm been grinding my head against an idea that is simple enough in my head, but I can't figure out how to implement in C++.
Normally, I can declare a class with a conversion operator like in this simple example:
class Foo
{
private:
int _i;
public:
Foo( int i ) : _i(i) { }
operator int( ) const
{
return i;
}
};
So now I can write awesome stuff like
int i = Foo(3);
But in my particular case, I would like to provide an operator for converting an object to a function pointer (e.g. converting a Bar instance to a int(*)(int, int) function pointer). Here's what I initially tried:
class Bar
{
private:
int (*_funcPtr)(int, int);
public:
Bar( int (*funcPtr)(int, int) ) : _funcPtr(funcPtr) { }
operator int(*)(int, int) ( ) const
{
return _funcPtr;
}
};
But the operator function fails to compile, with these errors being generated:
expected identifier before '*' token
'<invalid-operator>' declared as a function returning a function
I have also tried simple variations on the above, such as surrounding the return type in parenthesis, but all these ideas have also failed.
Does anyone know what the syntax is for declaring a conversion-to-function-pointer operator method, or whether it is even possible to do so?
Note: I am compiling this with Code::Blocks using GCC 4.5.2. Answers involving some of the new C++0x concepts are also welcome.
Edit
In my strive for simplifying the example, I unintentionally left out one detail. It's a bit weird, but rather than strictly returning an int(*)(int,int) pointer, the conversion operator is intended to be templated:
template<typename ReturnType, typename ArgType1, typename ArgType2>
operator ReturnType(*)(ArgType1, ArgType2) ( ) const
{
// implementation is unimportant here
}
As far as I know, I no longer cannot typedef such a type. This clearly makes things much more clumsy, but I hope that there is still a way.
Since you must know:
(*operator int() const)(int, int)
{
return _funcPtr;
}
(Fixed. Again.)
Update: I've been informed by Johannes Schraub and Luc Danton that this syntax is in fact not valid, and that you really must use a typedef. Since you say that typedefs aren't an option, here's a helper class that can wrap your typedef:
template<typename R, typename A1, typename A2>
struct MakeFunctionType
{
typedef R(*type)(A1, A2);
};
template<typename R, typename A1, typename A2>
operator typename MakeFunctionType<R, A1, A2>::type () const
{
// implementation is unimportant here
}
Use a typedef. It's easier to read, anyway:
class Bar
{
public:
typedef int (*fptr_t)(int, int);
Bar(fptr_t funcPtr) : _funcPtr(funcPtr) { }
operator fptr_t() const
{
return _funcPtr;
}
private:
fptr_t _funcPtr;
};
[edit]
For your template case I do not see how to use a typedef. #Kerrik gives the (messy) version of the syntax that should work.
EDIT:
Since your class has a non template function pointer assigned at constuction:
private:
int (*_funcPtr)(int, int);
It is not at all possible to later convert that to a function pointer of any type.
I will therefore assume that you meant a template class member operator overload, not a class template member operator overload.
Template version:
template<typename ReturnType, typename ArgType1, typename ArgType2>
class Bar {
public:
typedef ReturnType (*fptr_t)(ArgType1, ArgType2);
operator fptr_t ( ArgType1 arg1, ArgType2 arg2 ) const
{
// implementation is unimportant here
}
//etc...
};
Then used like this:
//create functor to some function called myfunc
Bar::fptr_t func_ptr = Bar<int, int, int>(&myfunc);
//call functor
int i = func_ptr(1,2);
If you want to make the code readable, you need to use a typedef. I don't even use functions pointers without typedef'ing them, the syntax is too horrid.
Goal:
template<typename ReturnType, typename ArgType1, typename ArgType2>
operator ReturnType(*)(ArgType1, ArgType2) ( ) const
{
return 0;
}
Path:
// 1: helper structure
template <typename R, typename A0, typename A1>
struct helper {
typedef R (*type)(A0,A1);
};
// 2: operator
template <typename R, typename A0, typename A1>
operator typename helper<R, A0, A1>::type() const {
return 0;
}
Check it out on ideone!
In C++11, it is possible to use an alias template to convert to any function, bypassing the need for custom type trait structs.
class Bar
{
private:
template<typename ReturnType, typename ArgType1, typename ArgType2>
using funcptr = ReturnType(*)(ArgType1, ArgType2);
public:
template<typename ReturnType, typename ArgType1, typename ArgType2>
operator funcptr<ReturnType, ArgType1, ArgType2> ( ) const;
};
To limit this to just int(*)(int, int), we can use SFINAE or static_assert.
The following works in GCC:
template<typename ReturnType, typename ArgType1, typename ArgType2>
operator decltype((ReturnType(*)(ArgType1, ArgType2)) nullptr)() const
{
// ...
}
How do I specialize a template for a set of data types? For example:
template<typename T>
inline T getRatio(T numer, T denom){
return (numer/denom);
}
I want to specialize it for a set of data types so it only works with int, long, double and float. So if the user would try to use this function with a char type, the compiler would throw error.
It depends on what you want to do. If you want the compiler to simply fail to find an appropriate resolution for the function call you could use Flinsch's answer, which is probably best, or you can use SFINAE:
template < typename T > is_an_ok_type : boost::mpl::false_ {};
template < > is_an_ok_type<int> : boost::mpl::true_ {};
... etc...
template < typename T >
typename boost::enable_if< is_an_ok_type<T>,T >::type
get_ratio(T t1, T t2)
{
return t1/t2;
}
If you want some sort of reasonably readable error instead you use a static assert; either static_assert (C++0x) or BOOST_STATIC_ASSERT.
you might do this:
// declaration
template <typename T> inline T getRatio(T numer, T denom);
// specialization for long
template <>
inline long getRatio<long>(long numer, long denom) { return (numer / denom); }
// specialization for float
template <>
inline float getRatio<float>(float numer, float denom) { return (numer, denom); }
// specialization for double
template <>
inline double getRatio<double>(double numer, double denom) { return (numer / denom); }
this will result in a linker error if getRatio is called with a type other than long, float or double.
If you want to restrict your getRatio() function only for int, long, double and float, then you can use this function as well. It will generate "a meaningful" compilation error if you call it with,say, char type argument. The compilation error would be : this_type_is_not_allowed_in_getRatio .
//yourheader.h
template<typename T>
inline T getRatio(T numer, T denom)
{
typedef typelist<int, typelist<long, typelist<double, float>>> allowedtypes;
compile_time_checker<contains<allowedtypes, T>::result> this_type_is_not_allowed_in_getRatio;
return (numer/denom);
}
It uses this header:
//metafunctions.h
template<typename H, typename T>
struct typelist
{
typedef H Head;
typedef T Tail;
};
template<typename T, typename Tail>
struct contains
{
static const bool result = false;
};
template<typename Head, typename Tail, typename T>
struct contains<typelist<Head, Tail>, T>
{
static const bool result = false || contains<Tail, T>::result;
};
template<typename T, typename Tail>
struct contains<typelist<T, Tail>, T>
{
static const bool result = true || contains<Tail, T>::result;
};
template<bool b> struct compile_time_checker;
template<> struct compile_time_checker<true> {};
Hope, it helps you. You can write all your code in just one function now!
As only the three data types long, double and float are relevant and their is no need for an additional generic version, just reject the template and provide three functions for long, double and float.
There's no way built into the language to specify that a template can only be instantiated with a certain set of type parameters. However, this will fail to compile for any type that does not have an operator / defined, which may be enough for you.
When designing APIs, it's considered good practice to avoid surprising your user, and most users would be surprised if you told them they weren't allowed to compute the ratio of two things that can be divided!
If you really don't want the default behavior, Flinsch's answer is a good compromise.