template argument list interconnected generic structs - c++11

I am attempting to write a small unit library to familiarize myself with generic programming and implicit conversion. I have chosen to organize the units into structs under their respective dimension. In order to implicitly convert between the units, a constructor is created for the compatible units. Before applying a template that is meant to allow any number type to occupy lengthValue, the code segment was happy. I now get the error below but I do not know how to approach resolving it.
#include <type_traits>
class Distance
{
template<typename GenericNumber, typename = typenamestd::enable_if<std::is_arithmetic<GenericNumber>::value, GenericNumber>::type> struct feet;
template<typename GenericNumber, typename = typename std::enable_if<std::is_arithmetic<GenericNumber>::value, GenericNumber>::type> struct inches;
template<typename GenericNumber, typename = typename std::enable_if<std::is_arithmetic<GenericNumber>::value, GenericNumber>::type>
struct feet
{
public:
feet(GenericNumber _distance);
feet(feet& _distance);
feet(inches _distance);
inline GenericNumber getLength() { return lengthValue; }
private:
GenericNumber lengthValue = 0.0;
};
template<typename GenericNumber, typename = typename std::enable_if<std::is_arithmetic<GenericNumber>::value, GenericNumber>::type>
struct inches
{
public:
inches(GenericNumber _distance);
inches(feet _distance);
inches(inches& _distance);
inline GenericNumber getLength() { return lengthValue; }
private:
GenericNumber lengthValue = 0.0;
};
};
errors:
Error C2955 use of class template requires template argument list
for lines
feet(inches _distance);
inches(feet _distance);

feet(inches<GenericNumber> _distance);
inches(feet<GenericNumber> _distance);
I needed to specify what type of the template I was referring to as a parameter, seems obvious now

Related

Compile time existence checking for a member function with signature fit to variadic parameters pack

I would like to check if there exist a member function with signature fit to a parameter pack. I began with the known SFINAE concept, while trying to extend it for considering also a parameters pack. But at this point I found that I don't know how to do it.
I try to do something like this:
// Note: T object may have several functions with the name foo, but with different signatures.
// a function foo also can be a template one with variadic parameters pack.
template<typename T, typename...Args>
class HAS_FUNCTION_FOO
{
template<typename U>
static bool test(decltype(&U::foo));
template<typename U>
static float test(...);
public:
static constexpr bool value = std::is_integral<decltype(test<T>(Args...))>::value;
//-------------------------------------------------------------^^^^^^^^^
// how to do it?
};
I would like to use it for declaring specific object at compile time - something like this:
class Bar
{
public:
template<typename T, typename...Args>
void doSomthing(T* p, Args&&...parameters)
{
// get correct object type:
// if T has a function called foo with parameters fits for pack, then declare A, o.w declare B.
using ObjType = typename std::conditional<HAS_FUNCTION_FOO<T, Args>::value, A, B>::type;
// compute
ObjType::doSomthing(p, std::forward<Args>(parameters)...);
}
private:
struct A
{
template<typename T, typename...Args>
static void doSomthing(T* p, Args&&...parameters)
{
p->foo(std::forward<Args>(parameters)...);
}
};
struct B
{
template<typename T, typename...Args>
static void doSomthing(T* p, Args&&...parameters)
{
// do something else
}
};
};
Something like this, perhaps:
template<typename T, typename...Args>
class HAS_FUNCTION_FOO
{
template <typename U>
static std::true_type test(
typename std::enable_if<sizeof(
decltype(std::declval<U>().foo(std::declval<Args>()...))*) != 0>::type*
);
template <typename U>
static std::false_type test(...);
public:
static constexpr bool value = decltype(test<T>(nullptr))::value;
};
Demo

CRTP traits only working with templated derived class

I have seen an idiom for using Derived type traits in the base class of a CRTP pattern that looks like this:
template<typename Derived>
struct traits;
template<typename Derived>
struct Base {
using size_type = typename traits<Derived>::size_type;
};
template <typename T>
struct Derived1 : Base<Derived1<T>>{
using size_type = size_t;
void print(){ std::cout << "Derived1" << std::endl; }
};
template <typename T>
struct traits<Derived1<T>> {
using size_type = size_t;
};
int main()
{
using T = float;
Derived1<T> d1;
d1.print();
}
My understanding is that the purpose of the idiom is to delay the instantiation of the Base class's size_type. What I am confused by is the fact that this pattern only seems to work if the derived class is itself templated. For instance, if we change the code to:
template<typename Derived>
struct traits;
template<typename Derived>
struct Base {
using size_type = typename traits<Derived>::size_type;
};
struct Derived1 : Base<Derived1>{
using size_type = size_t;
void print(){ std::cout << "Derived1" << std::endl; }
};
template <>
struct traits<Derived1> {
using size_type = size_t;
};
int main()
{
Derived1 d1;
d1.print();
}
then we get the error
prog.cc: In instantiation of 'struct Base<Derived1>':
prog.cc:21:19: required from here
prog.cc:18:58: error: invalid use of incomplete type 'struct traits<Derived1>'
using size_type = typename traits<Derived>::size_type;
^
prog.cc:14:8: note: declaration of 'struct traits<Derived1>'
struct traits;
^~~~~~
prog.cc: In function 'int main()':
prog.cc:33:9: error: 'Derived1' is not a template
Derived1<float> d1;
Could somebody give me an explanation indicating why the templated derived class compiles, but the untemplated class does not?
The issue you're seeing has nothing to do with CRTP.
Here's what the standard mentions.
If a class template has been declared, but not defined, at the point of instantiation (13.7.4.1),
the instantiation yields an incomplete class type (6.7). [Example:
template<class T> class X; X<char> ch; // error: incomplete type
X<char>
Your traits has only been declared at the point of instantiation of Base<Derived>, hence as per the standard(see above extraction from the standard), struct traits<Derived> yields an incomplete type.
You should reorder the code so that it sees the traits<Derived> specialization when Base<Derived> gets instantiated.
The compilation error you are seeing has nothing to do with CRTP, it's just a bit of a mish-mash of dependencies.
In the code without the templation, your "Base" struct needs the definition of the specialized "traits" struct but it only appears afterwards, so it tries to use the incomplete type it saw in the declaration above.
To get the code to work you need to have the "traits" specialization before the Base declaration, which requires you to also add a declaration of Derived 1, here is a compiling code:
class Derived1;
template<typename Derived>
struct traits;
template <>
struct traits<Derived1> {
using size_type = size_t;
};
template<typename Derived>
struct Base {
using size_type = typename traits<Derived>::size_type;
};
struct Derived1 : Base<Derived1>{
using size_type = size_t;
void print(){ std::cout << "Derived1" << std::endl; }
};
int main()
{
Derived1 d1;
d1.print();
}

How to make a particular constructor on a tempate type available only for a particular specialization in C++11?

I have a C++11 template that can be specialized with an arbitrary type parameter.
template<class ElementType>
class Foo
How do I declare a constructor that appears for the compiler's consideration only when ElementType is e.g. const uint8_t?
That is, I have a bunch of constructors that are generic over any ElementType, but I also want to have constructors that are only considered when ElementType is specialized in a particular way. (Allowing those constructors to be selected for other types would be unsafe.)
So far std::enable_if examples that I've found have been conditional on the types of the arguments of the constructors.
template<class ElementType>
struct Foo
{
template <typename T = ElementType>
Foo(typename std::enable_if<!std::is_same<T, const uint8_t>{}>::type* = nullptr) {}
template <typename T = ElementType>
Foo(typename std::enable_if<std::is_same<T, const uint8_t>{}>::type* = nullptr) {}
};
int main()
{
Foo<int> a{}; // ok, calls first constructor
Foo<const uint8_t> b{}; // ok, calls second constructor
}
wandbox example
You can break the class into two classes. The derived class' purpose is to be able to specialize constructors for different types. E.g.:
#include <cstdio>
#include <cstdint>
template<class ElementType>
struct Foo_
{
Foo_() { std::printf("%s\n", __PRETTY_FUNCTION__); }
};
template<class ElementType>
struct Foo : Foo_<ElementType>
{
using Foo_<ElementType>::Foo_; // Generic version.
};
template<>
struct Foo<uint8_t> : Foo_<uint8_t>
{
Foo() { std::printf("%s\n", __PRETTY_FUNCTION__); } // Specialization for uint8_t.
};
int main(int ac, char**) {
Foo<int8_t> a;
Foo<uint8_t> b;
}
The benefit of using the derived class here compared to enable_if is that:
The class can be partially specialized.
Only one specialization of the class is chosen for particular template parameters, rather than a set of constructors. When adding specializations for new types the existing enable_if expressions may need to be changed to make them more restrictive to avoid function overload set resolution ambiguity.

Using iterator_traits to deduce value type from pair of iterators

I have a type
typedef std::pair<ConstIterator, ConstIterator> Range;
with
typedef typename std::vector<T>::const_iterator ConstIterator;
I would now like to use std::iterator_traits to deduce the type the iterators of a Range are pointing to.
Could anybody please tell me how I can achieve this, from an object of type Range?
You can write a type trait, partially specialized on a pair:
template <typename T>
struct value_type {
using type = typename std::iterator_traits<T>::value_type;
};
template <typename T>
struct value_type<std::pair<T, T>>
: value_type<T>
{ };
This will support both your pair based ranges, and most iterables:
template<class R>
struct value_type {
using iterator_type = decltype( std::begin(std::declval<R>()) );
using type=typename std::iterator_traits<iterator_type>::value_type;
};
template<class It>
struct value_type<std::pair<It,It>> {
using type=typename std::iterator_traits<It>::value_type;
};
template<class X>
using value_t = typename value_type<X>::type;
note that the value type of a const iterator is a non-const value.
The above is not SFINAE friendly -- an industrial quality one would be.
You're explicitly allowed to add template specializations to the std namespace for user-defined types (thanks Barry for the precision !). If you rework your Range to be an actual type (not just a typedef), you can do this :
struct Range : std::pair<ConstIterator, ConstIterator> {
using std::pair<ConstIterator, ConstIterator>::pair;
};
namespace std {
template <>
struct iterator_traits<Range> : iterator_traits<ConstIterator> {};
}
When you buff your Range a bit, I expect this to evolve into :
namespace std {
template <class T>
struct iterator_traits<Range<T>> : iterator_traits<T> {};
}

Variadic typedefs, or "Bimaps done the C++0x way"

Short question: Can I typedef a variadic argument pack? I need template <typename ...T> struct Forward { typedef T... args; };.
Long version:
I was thinking about reimplementing the excellent boost bimap in C++0x. Recall that a bimap of two types S and T is a std::set of relations between S x and T y. The objects themselves are stored in two independent internal containers, and the relations track the associated iterators I suppose; both types can serve as keys via "left" and "right" lookup. Depending on the choice of internal containers, values may be unique or not, e.g. if the left container is a set and the right container is a multiset, then one x can map to many different ys, and right lookup gives an equal-range. Popular internal containers are set, multiset, vector and list, and maybe the unordered_* versions too.
So we need a type which accepts two containers as template parameters:
class Bimap<S, T, std::set, std::multiset>
But we must accept that the containers can take arbitrary many arguments, so we need to pass all those, too. If we just needed one set of variadic arguments, it wouldn't be a problem, since we could pass those directly. But now we need two sets of arguments, so I want to write a forwarder, to be used like so:
Bimap<int, int, std::set, std::set, Forward<std::less<int>, MyAllocator>, Forward<std::greater<int>, YourAllocator>> x;
Here's the template I came up with:
#include <set>
#include <cstdint>
template <typename ...Args>
struct Forward
{
typedef Args... args; // Problem here!!
static const std::size_t size = sizeof...(Args);
};
template <typename S, typename T,
template <typename ...SArgs> class SCont,
template <typename ...TArgs> class TCont,
typename SForward = Forward<>, typename TForward = Forward<>>
class Bimap
{
typedef SCont<S, typename SForward::args> left_type;
typedef TCont<T, typename TForward::args> right_type;
template <typename LeftIt, typename RightIt> struct Relation; // to be implemented
typedef Relation<typename left_type::const_iterator, typename right_type::const_iterator> relation_type;
};
int main()
{
Bimap<int, int, std::set, std::set, Forward<std::less<int>>, Forward<std::greater<int>>> x;
}
Unfortunately, in the indicated line in Forward I cannot figure out how to typedef the parameter pack! (The commented line gives a compiler error.)
[I suppose I could go for a lazy version Bimap<std::set<int, MyPred>, std::multiset<char, YourPred>> x; and extract the types via LeftCont::value_type and RightCont::value_type, but I thought it'd be nicer if I could make the key types my primary template arguments and allow defaulting to std::set containers.]
You can achieve what you want by encapsulating the variadic argument pack in a tuple and later using the following two helper template structs to forward the actual variadic arguments:
template<typename PackR, typename PackL>
struct cat;
template<typename ...R, typename ...L>
struct cat<std::tuple<R...>, std::tuple<L...>>
{
typedef std::tuple<R..., L...> type;
};
and
template<typename Pack, template<typename ...T> class Receiver>
struct Unpack;
template<typename ...Args, template<typename ...T> class Receiver>
struct Unpack<std::tuple<Args...>, Receiver>
{
typedef Receiver<Args...> type;
};
your code sample would look like this:
#include <set>
#include <cstdint>
#include <tuple>
template<typename PackR, typename PackL>
struct Cat;
template<typename ...R, typename ...L>
struct Cat<std::tuple<R...>, std::tuple<L...>>
{
typedef std::tuple<R..., L...> type;
};
template<typename Pack, template<typename ...T> class Receiver>
struct Unpack;
template<typename ...Args, template<typename ...T> class Receiver>
struct Unpack<std::tuple<Args...>, Receiver>
{
typedef Receiver<Args...> type;
};
template<typename ...Args>
struct Forward
{
//typedef Args... args; // Problem here!!
typedef std::tuple<Args...> args; // Workaround
static const std::size_t size = sizeof...(Args);
};
template<typename S, typename T,
template<typename ...SArgs> class SCont,
template<typename ...TArgs> class TCont,
typename SForward = Forward<> ,
typename TForward = Forward<>>
class Bimap
{
//typedef SCont<S, typename SForward::args> left_type;
//typedef TCont<T, typename TForward::args> right_type;
typedef typename Unpack<typename Cat<std::tuple<S>, typename SForward::args>::type, SCont>::type left_type; //Workaround
typedef typename Unpack<typename Cat<std::tuple<T>, typename TForward::args>::type, TCont>::type right_type; //Workaround
template<typename LeftIt, typename RightIt> struct Relation; // to be implemented
typedef Relation<typename left_type::const_iterator, typename right_type::const_iterator> relation_type;
};
int main()
{
Bimap<int, int, std::set, std::set, Forward<std::less<int>> , Forward<std::greater<int>>> x;
}
which compiles just fine under gcc 4.6.0
You can typedef a tuple. However, I wouldn't know how to then get the types back out again.
The easiest thing to do would be to just accept two full types.

Resources