We are trying to refactor our code and one of the improvements we want is the following: many functions have many arguments but many of them share a common subset. So, we would like to create a structure that would group them. The problem is that some functions need some of the parameters to be const and some not. Some of these functions must be able to call a subset of these functions supplying this parameter-grouping structure, but under the following restriction: a called function cannot "degrade" the constness of this structure (see the following example). Implementing all required variations of this struct solves the problem but not elegantly. One solution we're working on is to use templates, e.g:
template<class A, class B, class C>
struct my_container
{
A a;
B b;
C c;
};
void foo1(my_container<int, char, float const> & my_cont)
{
}
void foo2(my_container<int const, char, float const> & my_cont)
{
// This should NOT be allowed: we do mind something being const to be treated by the
// called function as non-const.
foo1(my_cont);
}
void foo3(my_container<int, char, float> & my_cont)
{
// This should be allowed: we don't mind something being non-const to be treated by the
// called function as const.
foo2(my_cont);
}
Our problem is that foo2 calls foo1 without the compiler complaining, and we'd like the exact opposite. Is this even possible to implement with templates? Is there any other technique?
Neither should work. Different instantiations of a template are
unreleated types, with no implicit conversions between them. So
my_container<int, char, float const>, my_container<int const, char,
float const> and my_container<int, char, float> are all unrelated
types, with no implicit conversions between them.
It should be possible to work out something using inheritance, using
metaprogramming tricks to determine what you inherit from, but I'm not
sure how, and I suspect that it would be more effort than it's worth.
Without bordering on undefined behavior, this can be achieved with another level of indirection. Add a view class which references the original members. Constness can be added implicitly, but cannot be removed.
template<class A, class B, class C>
struct my_container
{
A a;
B b;
C c;
};
template <class A, class B, class C>
class my_container_view
{
A* a_;
B* b_;
C* c_;
public:
template <class A_, class B_, class C_>
my_container_view(my_container<A_, B_, C_>& source):
a_(&source.a), b_(&source.b), c_(&source.c)
{}
template <class A_, class B_, class C_>
my_container_view(my_container_view<A_, B_, C_>& source):
a_(&source.a()), b_(&source.b()), c_(&source.c())
{}
A& a() const { return *a_; }
B& b() const { return *b_; }
C& c() const { return *c_; }
};
void foo1(my_container_view<int, char, float const> my_cont)
{
my_cont.a() = 10;
my_cont.b() = 'a';
my_cont.c() /*= 3.14*/;
}
void foo2(my_container_view<int const, char, float const> my_cont)
{
my_cont.a() /*= 10*/;
my_cont.b() = 'a';
my_cont.c() /*= 3.14*/;
//foo1(my_cont); //not allowed
}
void foo3(my_container_view<int, char, float> my_cont)
{
my_cont.a() = 10;
my_cont.b() = 'a';
my_cont.c() = 3.14;
t
foo2(my_cont);
}
int main()
{
my_container<int, char, float> mc;
foo1(mc);
foo2(mc);
foo3(mc);
}
(I have my doubts, though, how much this is worth. Normally with classes, either you can modify all its members - and you just don't modify the ones you don't want to -, or you can't modify any. If you want this level of control, you'd rather pass each argument separately - the opposite of what you are doing.)
My solution with a bit meta-programming. Looks pretty ugly and not throughoutly tested, but anyways:
This way, everything should work in general "out of the box"
#include <iostream>
#include <boost/type_traits.hpp>
template<class A, class B, class C>
struct my_container
{
A a;
B b;
C c;
template<typename An, typename Bn, typename Cn>
operator my_container<An,Bn,Cn>& ()
{
/* First, check whether compatible at all */
BOOST_STATIC_ASSERT((boost::is_same<typename boost::remove_cv<A>::type, typename boost::remove_cv<An>::type>::value));
BOOST_STATIC_ASSERT((boost::is_same<typename boost::remove_cv<B>::type, typename boost::remove_cv<Bn>::type>::value));
BOOST_STATIC_ASSERT((boost::is_same<typename boost::remove_cv<C>::type, typename boost::remove_cv<Cn>::type>::value));
/* Enforce const'ness */
BOOST_STATIC_ASSERT( !boost::is_const<A>::value || boost::is_const<An>::value );
BOOST_STATIC_ASSERT( !boost::is_const<B>::value || boost::is_const<Bn>::value );
BOOST_STATIC_ASSERT( !boost::is_const<C>::value || boost::is_const<Cn>::value );
return *reinterpret_cast< my_container<An,Bn,Cn>* >(this);
}
};
void foo1(my_container<int, char, float const> & my_cont)
{
}
void foo2(my_container<int const, char, float const> & my_cont)
{
// This should NOT be allowed: we do mind something being const to be treated by the
// called function as non-const.
//foo1(my_cont); /// BOOST_STATIC_ASSERT fails! Hurray!
}
void foo3(my_container<int, char, float> & my_cont)
{
// This should be allowed: we don't mind something being non-const to be treated by the
// called function as const.
foo2(my_cont); /// No complaints! Hurray!
}
int main(int argc, char* argv[])
{
my_container<int,char,float> foobar;
foo3(foobar);
return 0;
}
Related
Let we have a class with n fields. Each field can be moved. So do we have to explicitly define 2^n constructors?
The example with n=2:
struct A{
std::vector<B> a;
std::shared_ptr<B> b;
A(std::vector<B> &a, std::shared_ptr<B> &b):a(a),b(b){};
A(std::vector<B> &a, std::shared_ptr<B> &&b):a(a),b(std::move(b)){};
A(std::vector<B> &&a, std::shared_ptr<B> &b):a(std::move(a)),b(b){};
A(std::vector<B> &&a, std::shared_ptr<B> &&b):a(std::move(a)),b(std::move(b)){};
};
....
A aaa({{},{}}, shared_ptr<B>(new B()));
std::shared_ptr<B> b = ....;
A bbb({{},{}}, b);
You can work around it by having a perfect-forwarding template constructor:
struct A {
std::vector<B> a;
std::shared_ptr<B> b;
template <typename AA, typename BB> A(AA&& a, BB&& b) :
a(std::forward<AA>(a)), b(std::forward<BB>(b)) { }
};
If you need stricter parameter types requirement, you can also add enable_if or static_assert.
Here's a little explanation how perfect forwarding works:
void func1(int&&) { }
template <typename A> void func2(A&& t) {
func3(t);
func4(std::forward<A>(t);
}
template <typename B> void func3(B&&) { }
template <typename C> void func4(C&&) { }
int foo;
const int bar;
func1(foo); // ERROR
func1(bar); // ERROR
func1(std::move(foo)); // OK
func2(foo); // OK, A = int&, B = int&, C = int&
func2(bar); // OK, A = const int&, B = const int&, C = const int&
func2(std::move(foo)); // OK, A = int&&, B = int&, C = int&& <- note how && collapses to & without std::forward
You're defining the special member functions incorrectly, copy/move constructor is not defined in terms of class members, it defined in terms of the class.
instead of
class_name(const member_1&, ..., const member_n&)
class_name(const member_1&&, ..., const member_n&&)
you have to define your copy/move constructor as:
class_name(const class_name&) // copy-constructor
class_name(class_name&&) // move constructor
and inside it, use copy/move semantic. see c++draft class.copy
Consider the following code:
#include <boost/range.hpp>
#include <boost/iterator/counting_iterator.hpp>
typedef boost::iterator_range<boost::counting_iterator<int>> int_range;
template <typename T>
class Ref {
T* p_;
public:
Ref(T* p) : p_(p) { }
/* possibly other implicit conversion constructors,
but no unconstrained template constructors that don't
use the explicit keyword... */
operator T*() const { return p_; }
operator const T*() const { return p_; }
};
struct Bar { };
class Foo {
public:
Foo(int a, char b) { /* ... */ }
Foo(int a, const Ref<Bar>& b) { /* ... */ }
Foo(int a, const int_range& r) { /* ... */ }
};
int main() {
Bar b;
Foo f(5, &b);
return 0;
}
This code doesn't compile because the use of the Foo constructor is ambiguous, since boost::iterator_range apparently has a templated constructor that takes a single argument and is not declared as explicit. Assuming that changing the structure of Ref is not an option, how can I fix this problem? I came up with the following possible solution, but it's ugly and not easily maintainable, especially if there are more than a few constructors of Foo:
template<typename range_like>
Foo(
int a,
const range_like& r,
typename std::enable_if<
not std::is_convertible<range_like, Ref<Bar>>::value
and std::is_convertible<range_like, int_range>::value,
bool
>::type unused = false
) { /* ... */ }
or similarly
template<typename range_like>
Foo(
int a,
const range_like& r,
typename std::enable_if<
std::is_same<typename std::decay<range_like>::type, int_range>::value,
bool
>::type unused = false
) { /* ... */ }
which has the disadvantage that all other implicit type conversion for int_range is disabled, and thus relies on unspecified features of boost (and my instincts tell me it's probably a bad idea anyway). Is there a better way to do this? (C++14 "concepts-lite" aside, which is really what this problem wants I think).
I think this program is a minimal example of your problem:
#include <iostream>
struct T {};
struct A {
A(T) {}
};
struct B {
B(T) {}
};
struct C {
C(A const&) { std::cout << "C(A)\n"; }
C(B const&) { std::cout << "C(B)\n"; }
};
int main() {
C c{T{}};
}
You have two types A and B both implicitly convertible from another type T, and another type C implicitly convertible from A and B, but for which implicit conversion from T is ambiguous. You desire to disambiguate the situation so that C is implicitly convertible from T using the sequence of conversions T => A => C, but you must do so without changing the definitions of A and B.
The obvious solution - already suggested in the comments - is to introduce a third converting constructor for C: C(T value) : C(A(value)) {}. You have rejected this solution as not general enough, but without clarifying what the "general" problem is.
I conjecture that the more general problem you want solved is to make C unambiguously implicitly convertible from any type U that is implicitly convertible to A using the sequence of conversions U => A => C. This is achievable by introducing an additional template constructor to C (Live code demo at Coliru):
template <typename U, typename=typename std::enable_if<
!std::is_base_of<A,typename std::decay<U>::type>::value &&
std::is_convertible<U&&, A>::value>::type>
C(U&& u) : C(A{std::forward<U>(u)}) {}
The template constructor is a direct match for C(U), and so is unambiguously preferred over the C(A) and C(B) constructors that would require a conversion. It is constrained to accept only types U such that
U is convertible to A (for obvious reasons)
U is not A or a reference to A or a type derived from A, to avoid ambiguity with the C(const A&) constructor and infinite recursion in the case that U is e.g. A& or A&&.
Notably this solution does not require changing the definitions of T, A, B, C(A const&) or C(B const&), so it is nicely self-contained.
I need to create constructor taking two integers as arguments.
From there I need to call method taking these integers by reference. Inside this method I should dynamically convert integers into char* type (array of digits).
At the end of the constructor I should have two char* arrays instead of initial integers.
I kind of have to do it this way because the other class does the same thing but on structures. And save them into the template attributes.
I'm new to c++ language but my first guess was to use templates. I did a little research on the topic and found out it should work.
I'd love to compile the whole thing myself, but the mess with implementing c++ classes in my head produces quite long list of compile errors.
First question - can this be done using templates?
Second question, because I've already written something by myself:
template <class type> class Addition {
type num_a;
type num_b;
void convert(type, type);
public:
Addition(type, type);
}
template <class type> Addition::Addition(type a, type b) {
convert(&a, &b);
num_a = a;
num_b = b;
}
template <class type> Addition::convert(type *a, type *b) {
int temp_a = a, temp_b = b;
a = char[256], b = char[256];
// converting
}
Is this o.k., or did I do something wrong?
Do you have any suggestions about the way I implement classes in c++?
Why can't I initialize attribute with a value, like:
template <class type> class Addition {
type outcome = 0;
}
And if there's no need to use this keyword in c++, how do I do something like this?:
template <class type> Addition::Foo(type a, type b) {
this->a = a; // a = a;
this->b = b; // b = b;
}
Disclaimer: I cannot judge wheter you really need templates for what you are doing. That would depend on the number of different types that you want your Adddition class template to work with. If you will only use it for int, then perhaps this will introduce unnecessary complexity. You can always refactor later (this would be the Agile approach).
Having said that, if you want to use templates, the usual convention is to write T for a template parameter, and to use type for a nested typedef inside a class template. Using typename or class is a matter of taste, but typename stresses the fact that builtin types can also be passed as arguments. Note however that with template-template parameters you would need to write
template<template<typename> class U> SomeClass { /* your definition */ };
^^^^^ // <-- NOT typename here
which stresses the fact that only class templates can be passed as arguments.
There are a few other nitpicks that one could mention about your code that would make it fail to compile (missing return type in convert() and missing semi-colon in class definition):
template <typename T>
class Addition
{
static const std::size_t N = 256; // are you sure that 256 is all you'll ever need?
T num_a;
T num_b;
void convert(T const*, T const*); // by T const*, not T*
public:
Addition(T const&, T const&); // by T const&, not T
}; // <-- make sure to end class definitions with a semi-colon!
template <typename T>
Addition::Addition(T const& a, T const& b)
{
convert(&a, &b);
num_a = a;
num_b = b;
}
template <typename T>
void Addition::convert(T const* a, T const* b) // <-- use T const* if you don't modify the parameters
^^^^ // <-- you forgot the return type
{
int temp_a = a, temp_b = b;
a = char[N], b = char[N]; <-- hardcoded 256 is bad practice, better to keep that in 1 place only
// converting
}
In C++11 you can even use delegating constructors (supported by latest Visual C++ and of course gcc/Clang) and write
template <typename T>
Addition::Addition(T const& a, T const& b)
:
Addition(&a, &b) // delegate to the other constructor
{}
template <typename T>
Addition::Addition(T const* a, T const* b) // <-- use T const* if you don't modify the parameters
{
int temp_a = a, temp_b = b;
a = char[N], b = char[N]; <-- hardcoded 256 is bad practice, better to keep that in 1 place only
// converting
}
Finally, because template definition have to be in headers anyway, you could even write everything inside the class definition like this:
template <typename T>
class Addition
{
static const std::size_t N = 256; // are you sure that 256 is all you'll ever need?
T num_a;
T num_b;
Addition(T const*, T const*) // by T const*, not T*
{
int temp_a = a, temp_b = b;
a = char[N], b = char[N];
// converting
}
public:
Addition(T const&, T const&) // by T const&, not T
:
Addition(&a, &b) // delegate to the other constructor
{}
}; // <-- make sure to end class definitions with a semi-colon!
This saves you from tediously writing both declarations and definitions of all the member functions. For short and sweet classes (which you should strive for anyway) this is the preferred way of writing templates, but for very long definitions you might want to separate the declaration and definition.
Finally, as was explained by #tacp, you really need to use this->a to disambiguate a class data member from a function parameter. For that reason, people often write data members with a trailing underscore or a m_ prefix.
For your latter questions:
template <class type> class Addition {
//type outcome = 0;
//^^^^you have to call default constructor of type
type outcome = type();
}
It is better to use typename for convention, using class is also OK.
template <class type> Addition::Foo(type a, type b) {
this->a = a; // a = a;
this->b = b; // b = b;
}
If the passed parameter and member has the same name, you need to use this. You cannot do
a =a;
b =b;
since a,b are in local scope, but this->a means class member a.
Since you always want to convert integers to char array, I don't think you really need templates. Unless you would like convert double, float and other types into char* also in the future. I have not looked all the issues, so there may be others remain.
I was trying to built atop the thread here: Variable length template arguments list?
to have a default Functor class, this is only of academic interest. My goal is to build a generic Fucntor class: given a class name, method name and argument types(of variable length), it builds a class that has an operator() method which takes variable number of arguments of type specified in template args and takes a pointer and applies the given method. Imagine a class thus:
class MyClass
{
public:
float Fraction( float n, int m)
{
return n/m;
}
int Increment(int n)
{
return n+1;
}
} ;
And a templatized functor class that can be used in any function thus:
int k = FunctorClass<MyClass, Increment, int, int /*return type*/> (3);
assert(k == 4);
float l = FunctorClass<MyClass, Fraction, float, int, float, /*return type*/> (4,3);
assert(l == (4/3));
Can such a functor class be constructed?
Sidenote: Cant use Variadic templates, (building in VS2010, no ... template arguments)
Thanks for the help
This is certainly doable, e.g. Boost bind() uses this approach under the hood. Without variadics you won't get full generality, however, because you will be limited to a fixed number of template arguments and you need to type the implementation for each different number of arguments you want to support. Also, without rvalue references you won't get perfect forwarding.
That said, the way you are trying to use it won't work: when stating the member functions, you can't just name them. You need to obtain the correct member function point using e.g. &MyClass::Increment and &MyClass::Fraction. If the member function is overloaded, you need to disambiguate it.
Since you apparently want to enable the use of this function object for non-static member functions, you also need to provide an object on which the member function is to be called. The most reasonable approach for this is to pass a reference to the object as a constructor argument of the function object class and to store it to be used whenever the function is being called. That is, the use looks somewhat different but it can be simplified with some sort of factory function. Here is a version which adjusts the various things and implements a corresponding function object template:
#include <cassert>
// -----------------------------------------------------------------------------
template <typename T, T> class FunctorClass;
template <typename RC, typename Class,
RC (Class::*Member)()>
class FunctorClass<RC (Class::*)(), Member>
{
public:
FunctorClass(Class& object): object_(&object) {}
RC operator()() const { return (this->object_->*Member)(); }
private:
Class* object_;
};
template <typename RC, typename Class, typename A0,
RC (Class::*Member)(A0)>
class FunctorClass<RC (Class::*)(A0), Member>
{
public:
FunctorClass(Class& object): object_(&object) {}
RC operator()(A0 a0) const { return (this->object_->*Member)(a0); }
private:
Class* object_;
};
template <typename RC, typename Class, typename A0, typename A1,
RC (Class::*Member)(A0, A1)>
class FunctorClass<RC (Class::*)(A0, A1), Member>
{
public:
FunctorClass(Class& object): object_(&object) {}
RC operator()(A0 a0, A1 a1) const { return (this->object_->*Member)(a0, a1); }
private:
Class* object_;
};
// -----------------------------------------------------------------------------
class MyClass
{
public:
int foo() { return 17; }
float Fraction( float n, int m)
{
return n/m;
}
int Increment(int n)
{
return n+1;
}
};
int main()
{
MyClass object;
int i = FunctorClass<int (MyClass::*)(), &MyClass::foo>(object)();
assert(i == 17);
int k = FunctorClass<int (MyClass::*)(int), &MyClass::Increment>(object)(3);
assert(k == 4);
float l = FunctorClass<float (MyClass::*)(float, int), &MyClass::Fraction>(object)(4,3);
assert(l == (4.0f/3));
}
I'm not sure you would need variadics to pull this off. Consider the following interface...
template < typename RETURN_TYPE >
class iFunctor abstract {
public:
virtual RETURN_TYPE operator () ( void ) = 0;
};
Abstract interfaces are not full-blown classes, they can contain a partial implementation such as function signatures and some data members. With the template, you can generalized a return type. But what about the argument list you say?
Note how there is no constructor in the interface. In your concrete class (or derived classes) you can pass the burden of variable argument lists to the constructor, like so...
template < typename TYPE >
class ConcreteFunctor_add : public iFunctor < TYPE > {
private:
int A;
int B;
public:
explicit ConcreteFunctor_add ( const int &a, const int &b ) : A(a), B(b) {};
TYPE operator () ( void ) { return ( A + B ); };
};
You deal with the argument list on a case by case basis through the constructor.
The explicit constructor requires an argument list upon declaration, so you'll get your variable list here. So in practice...
ConcreteFunctor_add < int > addInteger ( 10, 10 );
addInteger();
...and you'd be cool.
I have a class A:
template <typename T, int I> struct A {};
and a class B. I would like object's of type B to implicitly convert to A when given as function arguments. B looks like this:
template <typename T>
struct B {
operator A<T,0> &() const { return *new A<T,0>(); }
};
However, my test (below) fails with GCC 4.5, giving the error: no matching function for call to 'test(B&)' Where am I going wrong here? Do other compilers also reject this?
template <typename T, int I>
void test(A<T,I> &a) { delete &a; }
int main(int argc, char *argv[])
{
B<int> b;
test(b);
return 0;
}
p.s. I've now put my own solution in an answer below.
Unrelated to your problem but return *new A<T,0>(); is wrong since it leaks memoryinvites a memory leak. You should not use new here. return A<T, 0>(); and removing the reference from the return type works just fine and does not leak memory.
If you want an implicit conversion from B to A you would need either:
A cast operator on B:
operator A<T,0>();
or an A constructor which takes a B reference:
A( const B& other );
or for B to derive from A. What you have declared:
operator A<T,0> &() const;
looks a bit like an ill-declared address-of overload.
However, since test() takes a reference (and non-const at that), the casting operator option won't work.
This is what I've tested:
template <typename T, int I> struct A {};
template <typename T>
struct B {
//operator A<T,0> &() const { return *new A<T,0>(); }
template< int I >
operator A<T, I> () const { return A< T, 0 >(); }
};
template <typename T, int I>
void test(A<T,I> &) { }
int f()
{
B<int> b;
A<int, 0> a( b );
test(a); // <-- Success
test(b); // <-- Failure, "could not deduce template argument"
return 0;
}
Conversion to A by initialising a local variable works fine.
Are you sure you actually want such an implicit conversion here? It sounds like a perfect way to confuse yourself or another maintainer, or worse, call a function using the wrong argument because the implicit conversion allows it. Instead, consider a make_A template like std::make_pair to explicitly show your intention at the call site.
Providing an overload of test like the following will enable to write
test(b) as in the question.
For example:
template <typename T>
void test(B<T> const &b) {
test( static_cast< A<T,0>& >( b ) );
}
test(b); // caller
If such overload isn't allowed but you are allowed to modify B's
definition, how about providing member function which returns A
like the following, instead of conversion function?
template <typename T>
struct B {
A<T,0> &to_A() const { return *new A<T,0>(); }
};
test( b.to_A() );
If you aren't allowed to modify B's definition, the above to_A will be
a free function like the following instead of member function:
template <typename T>
A<T,0> &to_A(B<T> const &b) {
return static_cast< A<T,0>& >( b );
}
test( to_A( b ) );
Hope this helps
This fails in VC++ too. To make it work, add this method:
template <typename T>
void test(B<T> &b)
{
test( static_cast< A<T,0>& > (b) );
}
This will take an actual B, explicitly do the conversion (via static_cast), and then call test using the A we just made.
I get errors when I run it though. I hope this is just example code, and you're not doing delete &a in your actual code. RobH gave a better conversion operator for you, and avoids the pointer messiness.
I've settled on using the pass by value conversion operator suggested by Konrad; the explicit template function call of Let_Me_Be; and I sprinkled a little bit of C++0x magic on top: an rvalue reference on the parameter to test. (Or, should that be C++ 2011 now?)
template <typename T, int I> struct A { int x; };
template <typename T>
struct B {
operator A<T,0> () const { return A<T,0>(); }
};
template <typename T, int I>
void test(A<T,I> &&a) { a.x=7; printf("%d\n", x); }
int main(int argc, char *argv[])
{
B<int> b;
test<int,0>(b);
return 0;
}