partial specialisation and nested templates - c++

I try to do partial specialisation for a template function where the specialized type T might also be a class template. However the following Code does not work.
#include <iostream>
#include <vector>
template <class T>
constexpr T neutral();
template <>
constexpr int neutral() { return 0; } // Okay. This is how partial specialisation works.
template <class U>
constexpr std::vector<U> neutral() { return std::vector<U>{ neutral<U>() }; }
int main()
{
const auto n{ neutral<std::vector<int>>() }; // error
}
main.cpp:16:19: error: call to 'neutral' is ambiguous
const auto n{ neutral<std::vector<int>>() }; // error
^~~~~~~~~~~~~~~~~~~~~~~~~
main.cpp:5:13: note: candidate function [with T = std::vector<int, std::allocator<int> >]
constexpr T neutral();
^
main.cpp:11:26: note: candidate function [with U = std::vector<int, std::allocator<int> >]
constexpr std::vector<U> neutral() { return std::vector<U>{ neutral<U>() }; } //error
^
My design goal is as follows: I provide an algorithm that can take any type that any programmer wants to use as long as he defines what the so called natural<T>() of his type T is. (However my actual code looks differently. This is a minimalistic example I tried to extract.)
How can it be implemented correctly?
I first thought, it must be something like
template <>
template <class U>
constexpr std::vector<U> neutral<std::vector<U>>() { return std::vector<U>{ neutral<U>() }; } //error
But this also ends up in errors:
main.cpp:11:26: error: function template partial specialization is not allowed
constexpr std::vector<U> neutral<std::vector<U>>() { return std::vector<U>{ neutral<U>() }; } //error
^ ~~~~~~~~~~~~~~~~
EDIT:
The context I want to use it is like this...
I have some class class Z7 which is representing a (math.) ring. I want to use something like the neutral in the example for the zero and the one element of the ring. Then there is a class
template <class _Ring>
class polynomial;
which will represent polynoms over the ring _Ring, e.g., 2x^5 + x^3 + 4x + 1. Therefore, polynomial<_Ring> will also be a ring whenever _Ring has been a ring. Thus I want to define a template specialisation for a zero and a one for polynomial<_Ring> by using the zero and one of type _Ring.

Functions need a difference in their parameters to have different definitions, classes/structs can be specialized without such a constraint, perhaps what you're looking for is closer to...
#include <vector>
template <typename T>
struct neutral;
template <typename T>
struct neutral {
static constexpr int get() { return 0; }
};
template <typename T>
struct neutral<std::vector<T>> {
static constexpr std::vector<T> get() { return std::vector<T>(); }
};
int main()
{
const auto n{ neutral<std::vector<int>>::get() };
const auto m{ neutral<float>::get() };
}

Related

How do I define a static member of a partial specialisation?

As pointed out in the comments, my problem is actually:
template <typename T, typename U>
struct X {
static int i;
};
template <typename U>
int X<int, U>::i = 42;
with compiler error:
error: template definition of non-template 'int X<int, U>::i'
7 | int X<int, U>::i = 42;
How can I define this static member?
Original question below.
My use case is maybe a little odd:
#include <string>
#include <map>
#include <functional>
#include <memory>
template<typename ResourceType,
typename AllocatorType>
class ResourceManager
{
public:
typedef std::string IDType;
typedef std::shared_ptr<ResourceType> ResourceHandle;
typedef std::function<ResourceType(const IDType&, AllocatorType)> LoadFunc;
static ResourceHandle GetResource(const IDType& id, AllocatorType& alloc)
{
auto itr = m_resources.find(id);
if(itr != m_resources.end())
return itr->second;
ResourceHandle r
= std::make_shared<ResourceType>(m_loadFunc(id, alloc));
m_resources[id] = r;
return r;
}
static std::map<IDType, ResourceHandle> m_resources;
static LoadFunc m_loadFunc;
};
struct PretendAllocator
{
};
struct SomeResource
{
int i;
};
template<typename Allocator>
SomeResource load_some_resouce_from_file(const std::string& filename,
Allocator& alloc)
{
SomeResource x;
x.i = 12;
// let's pretend that the allocator was used and the filename was used
return x;
}
template<typename Allocator>
using SomeResourceManager = ResourceManager<SomeResource, Allocator>;
template<typename Allocator>
typename SomeResourceManager<Allocator>::LoadFunc
SomeResourceManager<Allocator>::m_loadFunc
= [](const SomeResourceManager<Allocator>::IDType& id,
Allocator& alloc)
{
return load_some_resouce_from_file(id, alloc);
}
int main()
{
// I don't know what kind of allocator I may have in real-world
PretendAllocator pretendAllocator;
// But I would use it to allocate a resource managed through Manager
SomeResourceManager<PretendAllocator>::ResourceHandle resource
= SomeResourceManager<PretendAllocator>::GetResource("some file",
pretendAllocator);
return 0;
}
This throws a bunch of compiler errors.
main.cpp|61|error: template definition of non-template 'typename ResourceManager<SomeResource, Allocator>::LoadFunc ResourceManager<SomeResource, Allocator>::m_loadFunc'|
main.cpp|62|error: invalid use of incomplete type 'SomeResourceManager<Allocator>'|
main.cpp|8|note: declaration of 'SomeResourceManager<Allocator>'|
main.cpp|68|error: expected ',' or '...' before 'int'|
main.cpp|77|error: expected ')' at end of input|
main.cpp|62|note: to match this '('|
main.cpp|77|error: expected '{' at end of input|
My use case is that I would have multiple resources which are expensive to load/acquire. So the ResourceManager has some code around it that will only call the static std::function members when absolutely required (real-world is more complex than this example).
The above seemed like the best way to do this. Basically, when defining a Resource, you would also create an alias for a ResourceManager<YourResource> but I now have the added complexity of needing to include an Allocator.
How can I get the above to compile? I'm not sure exactly what the problem is. If it's not possible, would be great to hear an alternative.
You cannot partially specialise a member without partially specialising the entire class.
Insert a partial specialisation
template <typename U>
struct X<int, U> {
static int i;
};
before the definition of i and it should work.

Why is overload resolution is ambiguous in this case?

I've written this code to check if a class type have begin function.
struct foo //a simple type to check
{
int begin(){ return 0;}
};
struct Fallback
{
int begin(){ return 0;}
};
template<typename T>
struct HasfuncBegin : T,Fallback
{
typedef char one;
typedef int two;
template<typename X>
static one check(int (X::*)() = &HasfuncBegin<T>::begin);
template<typename X>
static two check(...);
enum :bool {yes = sizeof(check<T>())==1, no= !yes};
};
int main()
{
std::cout<< HasfuncBegin<foo>::yes;
return 0;
}
Which produces error :
error: call of overloaded 'check()' is ambiguous
enum {yes = sizeof(check<T>())==1, no= !yes};
^
C:\XXX\main.cpp:24:16: note: candidate: static HasfuncBegin<T>::one HasfuncBegin<T>::check(int (X::*)()) [with X = foo; T = foo; HasfuncBegin<T>::one = char]
static one check(int (X::*)() = &HasfuncBegin<T>::begin);
^
C:\XXX\main.cpp:26:16: note: candidate: static HasfuncBegin<T>::two HasfuncBegin<T>::check(...) [with X = foo; T = foo; HasfuncBegin<T>::two = int]
static two check(...);
^
Can anyone please explain why call is ambiguous (even though first check function with signature one check(int (X::*)() = &HasfuncBegin<T>::begin); has default argument to be used) and also how to make my code work?
Edit:
So here is final working code :
struct foo
{
int begin(){ return 0;}
};
struct Fallback
{
int begin(){ return 0;}
};
template<typename T, T ptr> struct dummy{};
template<typename T>
struct HasfuncBegin : T,Fallback
{
typedef char one;
typedef int two;
template<typename X>
static one check(dummy<int (X::*)(),&HasfuncBegin<X>::begin>*);
// even this won't work, so replace above statement with below commented one
// static one check(dummy<decltype(&HasfuncBegin<X>::begin),&HasfuncBegin<X>::begin>*);
template<typename X>
static two check(...);
enum {yes = sizeof(check<T>(0))==1, no= !yes};
};
The reason for the ambiguity is that both (templated) overloads of check() are valid matches for check<T>(). You may think one is more valid than the other but the rules of the language is that they are both equally valid.
A variable argument function (...) is a match for zero or more arguments (i.e. check<T>()). A function with a single argument that has a default value can match check<T>().
Hence the message about ambiguity.
You haven't actually described what you are trying to achieve with this code (particularly the initialisation of the enum), but are somehow expecting we will work out what you are trying to do. The obvious way to get it to compile would be to remove one of the overloads.
But, unless you describe what you are really trying to achieve, nobody can advise you. Reading sites like this does not grant people mindreading powers.
The call is ambiguous because overload selection is based on conversion sequences from the call arguments to the function parameters. The rules are a bit complex to fully explain here, but consider these two examples:
void ex1(int) {} //v1
void ex1(...) {} //v2
void ex2(int = 1) {} //v1
void ex2(...) {} //v2
int main() {
ex1(1);
ex2();
}
The ex1(1) call is well-formed. There is a single argument which has a better implicit conversion sequence to v1 than v2 (exact match vs. ellipsis conversion).
The ex2() call is ill-formed. There are no arguments with which to compare conversion sequences and both overloads can be called with no arguments. This is analogous to your code.
It looks like you're stuck with C++03, so here's a possible solution using this answer:
template<typename T>
struct HasfuncBegin {
typedef char yes[1];
typedef char no [2];
template <typename U, U> struct type_check;
template <typename _1> static yes &chk(type_check<int (T::*)(), &_1::begin > *);
template <typename > static no &chk(...);
static bool const value = sizeof(chk<T>(0)) == sizeof(yes);
};
Live Demo

Implicit conversion to template

My example below suggests that implicit conversions from non-template types to template types won't work as seamlessly as those only involving non-template types. Is there a way to make them work nonetheless?
Example:
struct point;
template<unsigned d> struct vec {
vec() { }
// ...
};
template<> struct vec<2> {
vec() { }
vec(const point& p) { /* ... */ } // Conversion constructor
// ...
};
struct point {
operator vec<2>() { return vec<2>(/* ... */); } // Conversion operator
};
template<unsigned d> vec<d> foo(vec<d> a, vec<d> b) {
return vec<d>(/* ... */);
}
template<unsigned d1, unsigned d2>
vec<d1 + d2> bar(vec<d1> a, vec<d2> b) {
return vec<d1 + d2>(/* ... */);
}
int main(int argc, char** argv) {
point p1, p2;
vec<2> v2;
vec<3> v3;
foo(v2, p1);
foo(p2, v2);
foo(p1, p2);
bar(v3, p1);
}
Is there a way to let this code auto-convert from point to vec<2>?
I know I can overload foo and bar to allow for point arguments, delegating to the vec implementation using an explicit conversion. But doing this for all parameter combinations will become tedious, particularly for functions with many such parameters. So I'm not interested in solutions where I have to duplicate code for every parameter combination of every function.
It appears that neither the conversion constructor nor the cast operator are sufficient to achieve this. At least my gcc 4.7.1 reports no matching function call, although it does name the desired function in a notice, stating that ‘point’ is not derived from ‘vec<d>’.
There is no direct way to get the conversion from point to vec<2>, because at the time when the function call foo(v1,p1) is processed, a function foo that expects a vec<2> as second argument does not exist yet. It's just a function template, and in order for this to be instantiated to a foo(const vec<2> &,const vec<2> &), a function call with these exact argument types would have to be given.
In order for the code to work, the compiler would have to guess both how to instantiate the template parameters, and what type the point argument to convert to. This is too much in the general case (although in your particular code it appears simple, because there is no other possible way to interpret the intent of the programmer).
In terms of solving this, the only thing I can think of is to create highly templated conversion functions:
template <typename T>
struct make_vec
{ };
template <unsigned d>
struct make_vec<vec<d>>
{
static constexpr unsigned dim = d;
using type = vec<dim>;
static const type &from(const type &v)
{ return v; }
};
template <>
struct make_vec<point>
{
static constexpr unsigned dim = 2;
using type = vec<dim>;
static type from(const point &p)
{ return type(p); }
};
template <typename T>
typename make_vec<typename std::decay<T>::type>::type make_vec_from(T&& arg)
{ return make_vec<typename std::decay<T>::type>::from(std::forward<T>(arg)); }
And then implement the foo and bar functions as general templates (accepting all kinds of types, not only vec<d>, using make_vec defined above to convert the given types to the right kind of vec<d>):
namespace detail {
/* Your original implementation of foo. */
template<unsigned d> vec<d> foo(vec<d>, vec<d>) {
return vec<d>(/* ... */);
}
}
/* Templated version of foo that calls the conversion functions (which do
nothing if the argument is already a vec<d>), and then calls the
foo() function defined above. */
template <typename T, typename... Ts>
typename make_vec<typename std::decay<T>::type>::type foo(T&& arg, Ts&&... args)
{ return detail::foo(make_vec_from(arg),make_vec_from(args)...); }
In the case of bar you also need a way to calculate the return type, which is vec<d1+d2+d3...>. For this, a sum calculator is required, also templated:
template <typename... Ts>
struct dsum {
static constexpr unsigned value = 0;
};
template <typename T, typename... Ts>
struct dsum<T,Ts...> {
static constexpr unsigned value = make_vec<typename std::decay<T>::type>::dim + dsum<Ts...>::value;
};
Then, the return type of bar() is vec<dsum<T,Ts...>::value>.
A fully working example is here: http://liveworkspace.org/code/nZJYu$11
Not exactly simple, but might be worth it if you really have extremely many different combinations of arguments.

C++ Forward non-template member function call to template function

I'd like to hide a std::tuple in my class 'Record' and provide an operator[] on it to access elements of the tuple. The naive code that does not compile is this:
#include <tuple>
template <typename... Fields>
class Record {
private:
std::tuple<Fields...> list;
public:
Record() {}
auto operator[](std::size_t n)
-> decltype(std::get<1u>(list)) {
return std::get<n>(list);
}
};
int main() {
Record<int, double> r;
r[0];
return 0;
}
g++ 4.6 says:
x.cc:13:32: error: no matching function for call to ‘get(std::tuple<int, double>&)’
x.cc:13:32: note: candidates are:
/usr/include/c++/4.6/utility:133:5: note: template<unsigned int _Int, class _Tp1, class _Tp2> typename std::tuple_element<_Int, std::pair<_Tp1, _Tp2> >::type& std::get(std::pair<_Tp1, _Tp2>&)
/usr/include/c++/4.6/utility:138:5: note: template<unsigned int _Int, class _Tp1, class _Tp2> const typename std::tuple_element<_Int, std::pair<_Tp1, _Tp2> >::type& std::get(const std::pair<_Tp1, _Tp2>&)
/usr/include/c++/4.6/tuple:531:5: note: template<unsigned int __i, class ... _Elements> typename std::__add_ref<typename std::tuple_element<__i, std::tuple<_Elements ...> >::type>::type std::get(std::tuple<_Elements ...>&)
/usr/include/c++/4.6/tuple:538:5: note: template<unsigned int __i, class ... _Elements> typename std::__add_c_ref<typename std::tuple_element<__i, std::tuple<_Elements ...> >::type>::type std::get(const std::tuple<_Elements ...>&)
Basically I'd like to call Record::operator[] just like on an array. is this possible?
The argument to get is a compile time constant. You cannot use a
runtime variable for this and you cannot have a single function that
returns the tuple members as your return type is going to be
wrong. What you can do is to abuse non-type argument deduction:
#include <tuple>
template<typename... Args>
struct Foo {
std::tuple<Args...> t;
template<typename T, std::size_t i>
auto operator[](T (&)[i]) -> decltype(std::get<i>(t)) {
return std::get<i>(t);
}
// also a const version
};
int main()
{
Foo<int, double> f;
int b[1];
f[b];
return 0;
}
This is so horrible, that I would never use it and it won't make much sense to users. I would just forward get through a template member.
I'll try to explain why I think why this is really evil: The return type of a function depends only on compile time facts (this changes slightly for virtual member functions). Let's just assume that non-type argument deduction were possible for some cases (the function call arguments are constexpr) or that we could build something that hides it reasonably well, your users wouldn't realize that their return type just changed and implicit conversion would do nasty things to them. Making this explicit safes some of the trouble.
The error message seems to be misleading, as the problem with your code is pretty much clear:
auto operator[](std::size_t n)
-> decltype(std::get<1u>(list)) {
return std::get<n>(list);
}
The template argument n to std::get must be a constant expression, but in your code above n is not a constant expression.
No.
It is not possible to use a parameter bound at runtime (such as a function parameter) to act as template parameter, because such need be bound at compile-time.
But let's imagine for a second that it was:
Record<Apple, Orange> fruitBasket;
Then we would have:
decltype(fruitBasket[0]) equals Apple
decltype(fruitBasket[1]) equals Orange
is there not something here that bothers you ?
In C++, a function signature is defined by the types of its arguments (and optionally the values of its template parameters). The return type is not considered and does not participate (for better or worse) in the overload resolution.
Therefore, the function you are attempting to build simply does not make sense.
Now, you have two alternatives:
require that all arguments inherit or be convertible to a common type, and return that type (which allows you to propose a non-template function)
embrace templates and require your users to provide specifically the index of the type they wish to use
I do not (and cannot) which alternative is preferable in your particular situation, this is a design choice you will have to make.
Finally, I will remark that you may be reasoning at a too low level. Will your users really need to access each field independently ? If they don't, you could provide facilities to apply functions (visitors ?) to each element in turn, for example.
I think Xeo had code which did this.
Here is my attempt which somewhat works. The problem is that [] is not a reference.
template<typename T, std::size_t N = std::tuple_size<T>::value - 1>
struct foo {
static inline auto bar(std::size_t n, const T& list)
-> decltype(((n != N) ? foo<T, N-1>::bar(n, list) : std::get<N>(list))) {
return ((n != N) ? foo<T, N-1>::bar(n, list) : std::get<N>(list));
}
};
template<typename T>
struct foo<T, 0> {
static inline auto bar(std::size_t n, const T& list)
-> decltype(std::get<0>(list)) {
return std::get<0>(list);
}
};
template <typename... Fields>
class Record {
private:
std::tuple<Fields...> list;
public:
Record() {
std::get<0>(list) = 5;
}
inline auto operator[](std::size_t n)
-> decltype(foo<decltype(list)>::bar(n, list)) {
return foo<decltype(list)>::bar(n, list);
}
};
int main() {
Record<int, double> r;
std::cout << r[0];
return 0;
}
As n is a template parameter, it should be known in compile time, but you want to pass it as a parameter in run-time.
Also, gcc 4.5.2 isn't happy due to this fact:
g++ 1.cpp -std=c++0x
1.cpp: In member function 'decltype (get<1u>(((Record<Fields>*)0)->Record<Fields>::list)) Record<Fields>::operator[](size_t)':
1.cpp:14:25: error: 'n' cannot appear in a constant-expression
If you're fine with a compile-time constant and still want to have the nice operator[] syntax, this is an interesting workaround:
#include <tuple>
template<unsigned I>
struct static_index{
static unsigned const value = I;
};
template <typename... Fields>
class Record {
private:
typedef std::tuple<Fields...> tuple_t;
tuple_t list;
public:
Record() {}
template<unsigned I>
auto operator[](static_index<I>)
-> typename std::tuple_element<
I, tuple_t>::type&
{
return std::get<I>(list);
}
};
namespace idx{
const static_index<0> _0 = {};
const static_index<1> _1 = {};
const static_index<2> _2 = {};
const static_index<3> _3 = {};
const static_index<4> _4 = {};
}
int main() {
Record<int, double> r;
r[idx::_0];
return 0;
}
Live example on Ideone. Though I'd personally just advise to do this:
// member template
template<unsigned I>
auto get()
-> typename std::tuple_element<
I, tuple_t>::type&
{
return std::get<I>(list);
}
// free function
template<unsigned I, class... Fields>
auto get(Record<Fields...>& r)
-> decltype(r.template get<I>())
{
return r.template get<I>();
}
Live example on Ideone.

C++ two or more data types in declaration

I'm getting a strange error from g++ 3.3 in the following code:
#include <bitset>
#include <string>
using namespace std;
template <int N, int M>
bitset<N> slice_bitset(const bitset<M> &original, size_t start) {
string str = original.to_string<char, char_traits<char>, allocator<char> >();
string newstr = str.substr(start, N);
return bitset<N>(newstr);
}
int main() {
bitset<128> test;
bitset<12> result = slice_bitset<12, 128>(test, 0);
return 0;
}
The error is as follows:
In function `std::bitset slice_bitset(const std::bitset&, unsigned int)':
syntax error before `,' token
`char_traits' specified as declarator-id
two or more data types in declaration of `char_traits'
`allocator' specified as declarator-id
two or more data types in declaration of `allocator'
syntax error before `>' token
It has to be something really silly, but I've already told it to my rubber duck and a friend to no avail.
Thanks, Lazyweb.
The selected answer from CAdaker solves the problem, but does not explain why it solves the problem.
When a function template is being parsed, lookup does not take place in dependent types. As a result, constructs such as the following can be parsed:
template <typename T>
class B;
template <typename T>
void foo (B<T> & b) {
// Use 'b' here, even though 'B' not defined
}
template <typename T>
class B
{
// Define 'B' here.
};
However, this "feature" has a cost, and in this case it is that the definition of 'foo' requires hints on the contents of the template 'B'. If 'foo' uses a nested type of 'B', then the typename keyword is required to tell the compiler that the name is a type:
template <typename T>
void foo (B<T> & b)
{
typename B<T>::X t1; // 'X' is a type - this declares t1
B<T>::Y * t1; // 'Y' is an object - this is multiplication
}
Without 'typename' in the above the compiler will assume that X is an object (or function).
Similarly, if a member function is called and the call has explicit template arguments then the compiler needs to know to treat the < as the start of a template argument list and not the less than operator:
template <typename T>
void foo (B<T> & b)
{
b.template bar<int> (0); // 'bar' is a template, '<' is start of arg list
b.Y < 10; // 'Y' is an object, '<' is less than operator
}
Without template, the compiler assumes that < is the less than operator, and so generates the syntax error when it sees int> since that is not an expression.
These hints are required even when the definition of the template is visible. The reason is that an explicit specialization might later change the definition that is actually chosen:
template <typename T>
class B
{
template <typename S>
void a();
};
template <typename T>
void foo (B<T> & b)
{
b.a < 10; // 'B<int>::a' is a member object
}
template <>
class B<int>
{
int a;
};
Use either just
original.to_string();
or, if you really need the type specifiers,
original.template to_string<char, char_traits<char>, allocator<char> >();
The following compiled for me (using gcc 3.4.4):
#include <bitset>
#include <string>
using namespace std;
template <int N, int M>
bitset<N> slice_bitset(const bitset<M> &original, size_t start)
{
string str = original.to_string();
string newstr = str.substr(start, N);
return bitset<N>(newstr);
}
int main()
{
return 0;
}