I am having trouble with some code.
'Bar' : cannot instantiate abstract class
I have (finally) been able to recreate the error in a small amount of code.
struct SomeStruct
{
// ******
};
template <typename TIN, typename TOUT, typename TINDEX>
struct IFoo
{
public:
virtual void add(const TIN item) = 0; // <-- BAD
//virtual void add(const TOUT& item) = 0; // <-- GOOD
// ******
};
template <typename TVALUE, typename TINDEX>
struct Bar : IFoo<TVALUE &, TVALUE, TINDEX>
{
public:
void add(const TVALUE& item)
{
// ******
}
// ******
};
int main(int argc, char *argv[])
{
SomeStruct someStruct;
Bar<SomeStruct, int> bar = Bar<SomeStruct, int>();
bar.add(someStruct);
// ******
}
Can anyone please advise WHY using a reference with the template parameter is causing this?
The issue here is that when you write const TIN and TIN is a reference type, the const applies to the reference and not to the value type.
This is why you are seeing different behaviour for const TIN and const TOUT& even when you think they should be the same.
A simple fix for this is to add the const to the value type in your IFoo instantiation:
struct Bar : IFoo<const TVALUE &, TVALUE, TINDEX>
// here ^^^^
Your problem goes back to basic concepts like function signature: a function signature/prototype is given by the function name, the number of parameters, datatype of parameters and the order of appearance of those parameters.
For any two functions if any of the above differ, than you are dealing with two different functions.
More exactly, these two represent two different signatures:
virtual void add(const TIN item) = 0;
virtual void add(const TOUT& item) = 0;
Since you implement only the second one in the derived class, you get the error.
We can simply your example further to:
template <typename T>
struct IFoo {
virtual void add(const T item) = 0;
};
template <typename T>
struct Bar : IFoo<T&> {
void add(const T& item) { }
};
In Bar, you are taking item as a reference to const T. In IFoo, you are declaring a pure virtual method that takes a const reference to T. But all references are inherently const, so that's redundant - it's equivalent to just taking a reference to T.
For Bar<int> - the signature of IFoo::add() is void add(int& ) whereas Bar::add() is void add(const int& ). Those signatures don't match - hence Bar is still an abstract class. Just one that hid IFoo::add().
If you have a C++11 compiler, you should prefer to add the override keyword to Bar::add() so that you would get a compiler error for:
main.cpp:15:10: error: 'void Bar<T>::add(const T&) [with T = int]' marked 'override', but does not override
void add(const T& ) override { }
^
Related
I have only recently started working with variadic templates.
Here is my problem:
I have a function called "addTo()" that adds a new object to a collection. The type of the object is the same as the type of the class the function resides in (its a template class). addTo() also uses a parameter pack to fill the constructor. addTo also recieves a key for the map (thats the collection). Now the collection stores the objects using a std::shared_ptr. Now to improve flexibility I want to add the ability to add a existing object to the collection, which will allow me to also add anything thats assignable.
here is an example (pseudo code)
class A{
//whatever
~~some function that can be overloaded
A(int,float);
}
class B:public A{
//whatever
~~overloads that function
}
//In some other function
AddToClass<A> instance;
instance.addTo(key,12,2.2); //this is how it already works
instance.addTo(key, new B(12,3.5)); //this is how I also want it to work
I dont know if this is achievable or how I can achieve this, however I beg you to explain the (possible) solution in detail since I still have loads of problems understanding parameter packs.
What I have tried
I tried using dynamic cast but I didnt manage to make it so that the
parameter pack gets expanded (because I don't really get how to use
them yet other than very basic function forwarding)
I tried just putting it in the std::make_shared call (the constructor) but that doesn't work because I don't want to force the types to have a constructor for each derived class (seems counter intuitive and bad practice)
Please explain to me how to do this (if its possible) in detail. It would really help me out a lot :)
---More info---
Here is an example of how the addToClass could look like (pseudo code, written from the top of my head):
template<class t>
class addToClass{
private:
std::map<key, shared_ptr<t>> collection;'
//sth else
public:
template<typename... Args>
void addTo(const Key &key, Args...args){
collection.insert(std::pair<key, shared_ptr<t>>(key,std::make_shared<t>(std::forward<Args>(args)...));
}
//other stuff
}
Now everything already works, all I want is that "addTo()" can also accept pointers of the type t or pointers to some class that derives from t. That would allow me to make the function a lot more flexible and save me loads of work in some cases.
If you want also that your client class can take pointers, you need SFINAE to disable your additional addTo function.
Full example:
class X {};
class A
{
public:
A( int, double) {}
A( X* ){}
};
class B: public A
{
public:
using A::A;
};
using Key = int;
template<class t>
class AddToClass
{
private:
std::map<Key, std::shared_ptr<t>> collection;
public:
template<typename... Args>
void addTo(const Key& key, Args...args)
{
collection.emplace( key, std::make_shared<t>(std::forward<Args>(args)...));
}
template < typename U, typename std::enable_if< std::is_base_of<t, U>::value, U>::type* = nullptr >
void addTo( const Key &key, U* ptr, X* = 0 )
{
collection.emplace( key, ptr );
}
};
int main()
{
AddToClass<A> instance;
Key key = 9;
instance.addTo(key,12,2.2); //this is how it already works
instance.addTo(key, new B{12,3.5}); //this is how I also want it to work
instance.addTo(key, new A{ new X});
instance.addTo(key, new B{ new X});
instance.addTo(key, new X);
}
If I understand correctly, your intention was to have a AddToClass<A>, not an AddToClass<int>.
In this case, I suggest to use emplace() instead of instert(), write your variadic method as follows
template <typename ... Args>
void addTo (Key const & key, Args && ... args)
{ collection.emplace(key,
std::make_shared<T>(std::forward<Args>(args)...)); }
and add a addTo() version for (derived from T) pointers
template <typename U>
void addTo (Key const & key, U * p)
{ collection.emplace(std::piecewise_construct,
std::forward_as_tuple(key),
std::forward_as_tuple(p)); }
If you want, you can add a std::enable_if to SFINAE enable the last method only if U is derived from T.
The following is a full working example
#include <map>
#include <memory>
struct A
{ A (int, float) {} };
struct B: public A
{ B (int i, float f) : A{i, f} {} };
using Key = int;
template <typename T>
class addToClass
{
private:
std::map<Key, std::shared_ptr<T>> collection;
public:
template <typename ... Args>
void addTo (Key const & key, Args && ... args)
{ collection.emplace(key,
std::make_shared<T>(std::forward<Args>(args)...)); }
template <typename U>
void addTo (Key const & key, U * p)
{ collection.emplace(std::piecewise_construct,
std::forward_as_tuple(key),
std::forward_as_tuple(p)); }
};
int main ()
{
addToClass<A> instance;
instance.addTo(1, 12,2.2);
instance.addTo(2, new B(12,3.5));
}
I have a struct made of templated types that work with incomplete types unless instantiated, like std::vector. Access into those types work with typesafe index wrappers. Example:
template<class T>
struct Idx{unsinged val;};
struct Holder{
MyVector<Foo> foos;
MyVector<Bar> bars;
};
const Foo& foo = holder.foos.get(Idx<Foo>(...));
This works well: Idx does not need to know the type of the template param because it is never used. Holder works with forward declarations of Foo/Bar too. I cannot confuse Idx<Foo> with Idx<Bar> because I can only get the respective type with them. Because this is so unique I though of adding convenience functions to holder:
struct Holder{
MyVector<Foo> foos;
MyVector<Bar> bars;
const Foo& get(Idx<Foo> idx) { return foos.get(idx);}
const Bar& get(Idx<Bar> idx) { return bars.get(idx);}
};
But now I need full types for Holder, which I wanted to avoid. Is it possible to use incomplete types AND the convenience functions? Maybe some templates help but I'd need some dispatch to either foos or bars which most likely instantiates it.
Maybe you can create a template function
template<typename T>
const T& getByIndex(const MyVector<T>& vec, const Idx<T>& idx)
{ return vec.get(idx); }
Then you can use it inside Holder like
const Foo& get(const Idx<Foo>& idx) { return getByIndex(foos, idx); }
Do not expect the parameter as instance Idx<Foo> because this would require the fully defined type (the reference allows incomplete types).
I found a solution during the discussion of then answer by #grek40 :
I need a templatized get function so the containers get function does not get instantiated in the header. Hence we have:
template<class T> const T& get(DescIdx<T> idx) const { return getContainer<T>().get(idx); }
Now we need a getContainer function which is simple: template<class T> const MyVector<T>& getContainer() const;
This needs to be instantiated for our containers like: template<> inline const MyVector<Foo>& Holder::getContainer() const { return foos; }
So all in all:
template<class T>
struct Idx{unsinged val;};
struct Holder{
MyVector<Foo> foos;
MyVector<Bar> bars;
template<class T> const T& get(DescIdx<T> idx) const { return getContainer<T>().get(idx); }
template<class T> const MyVector<T>& getContainer() const;
};
template<> inline const MyVector<Foo>& Holder::getContainer() const { return foos; }
template<> inline const MyVector<Bar>& Holder::getContainer() const { return bars; }
// Somewhere else
const Foo& foo = holder.get(Idx<Foo>(...));
This might be improved by using template metaprogramming. Steps:
Define a boost::mpl::list of all types (Foo, Bar)
Create a templatized struct MetaHolder that holds 1 MyVector<T>
Let Holder inherit from MetaHolder instantiated with each type
Implement 1(!) generic getContainer functions which simply returns MetaHolder<T>.container.
Everything will get resolved at compile time, so no runtime overhead. Not sure about compile time overhead though as Boost.MPL can get quite heavy.
Let's say I have this code:
class BaseObject
{
public:
virtual void OnDestroy() {}
};
template <typename T>
struct myArrayDeleter
{
void operator()(T *p, std::size_t count)
{
for(std::size_t i = 0; i < count; i++)
{
static_cast<BaseObject*>((void*)(int(p) + sizeof(T) * i))->OnDestroy();
}
delete [] p;
}
};
And let's assume that it works as intended (it's a simplified version, written now without the check but basically you know what this code should do).
With this part I don't have a problem. However, check this out:
class AActor
: public BaseObject
{
public:
virtual void OnDestroy() override
{
// some code here
}
};
template <typename T>
class SimplifiedHolder
{
protected:
std::shared_ptr<T> m_shared;
std::size_t m_size;
public:
// Some not important code here
// WE ASSUME HERE THAT IT ALWAYS HOLDS ARRAY
// sizeOfArray always > 1
template <typename U>
SimplifiedHolder(U *ptr, std::size_t sizeOfArray)
: m_size(sizeOfArray)
{
m_shared = std::shared_ptr<T>(ptr,
std::bind(&myArrayDeleter<U>(), std::placeholders::_1, m_size));
}
// And now as we initialize our shared_ptr with template
// we can check if it is exactly of type "U"
template <typename U>
bool IsExactlyOfType()
{
if(!m_shared)
return false;
return ((void*)std::get_deleter<myArrayDeleter<U>>(m_shared)) != nullptr;
}
};
However, the method IsExactlyOfType isn't working. That's because I initialized shared_ptr with std::bind. std::get_deleter always returns nullptr because the wrong type is specified in the template. I don't know what type to pass. I tried also with non-array code in which myDeleter is a functor with only one argument and it works perfectly with code like this:
template <typename U>
bool IsExactlyOfType()
{
if(!m_shared)
return false;
return ((void*)std::get_deleter<myDeleter<U>>(m_shared) != nullptr;
}
I know I could go with typeid(U) == typeid(*m_shared.get()) but this is not what I want. I have much more complicated code and in that case only this method is good.
Can a more experienced programmer tell me what type to specify to std::get_deleter?
It turned out that compiler wasn't translating decltype correctly. I tried to get deleter immediately after initializing shared_ptr and it worked. However the same decltype in function was generating slightly other type. I checked it in debugger and it generated this results:
In constructor:
std::_Binder<std::_Unforced,grim::impl::TObjectArrayDeleter<APlayer>,std::_Ph<1> const &,unsigned int &> &
In function:
std::_Binder<std::_Unforced,grim::impl::TObjectArrayDeleter<APlayer>,std::_Ph<1> const &,unsigned int const &> *
Take a look at the end - it appended additional const. I needed to change it manually, so now my code looks like this:
using D = std::_Binder<std::_Unforced,grim::impl::TObjectArrayDeleter<U>,
std::_Ph<1> const &,unsigned int &>;
return ((void*)std::get_deleter<D>(m_shared)) != nullptr;
Sorry if this is such an easy question, there must be something I don't understand about inheritance, virtual and override in c++. In the following example, I get a compile-time error relative to a virtual method that I specifically override to avoid such error in a child class. Am I doing something wrong?
#include <array>
#include <deque>
template <class T, class C>
struct foo
{
virtual const C& data() const =0;
inline virtual T& operator[] ( unsigned n ) const
{ return const_cast<T&>( data()[n] ); }
};
/**
* The implementation of foo::operator[] is useful for classes inheriting
* with simple sequence containers like:
* foo<T,std::deque<T>>, foo<T,std::vector<T>>, ..
*
* But the following requires operator[] to be redefined:
*/
template <class T, unsigned N>
struct baz
: public foo<T, std::deque<std::array<T,N>> >
{
typedef std::deque<std::array<T,N>> data_type;
data_type m_data;
inline const data_type& data() const
{ return m_data; }
inline virtual T& operator[] ( unsigned n ) const override
{ return const_cast<T&>( data()[n/N][n%N] ); }
};
int main()
{
baz<double,3> b; // throws an error relative to foo::operator[] depsite override
}
EDIT 1 The error:
clang++ -std=c++0x -Wall virtual_operator.cpp -o virtual_operator.o
virtual_operator.cpp:11:12: error: const_cast from 'const value_type' (aka 'const std::__1::array<double, 3>') to 'double &' is not allowed
{ return const_cast<T&>( data()[n] ); }
^~~~~~~~~~~~~~~~~~~~~~~~~~~
virtual_operator.cpp:26:8: note: in instantiation of member function 'foo<double, std::__1::deque<std::__1::array<double, 3>, std::__1::allocator<std::__1::array<double, 3> > > >::operator[]'
requested here
struct baz
^
1 error generated.
EDIT 2 I consider this to be part of the question; if compiling fails because foo::operator[] is still callable in baz, then why does it compile fine if I don't declare foo::operator[] as virtual (ie, hiding instead of overriding)?
The issue is that although you are only intending to call the derived operator[] function on baz instances, the compiler still needs to generate code for the base class because that function is still callable on baz instances. In this case, generating that code results in a type error, because you are trying to cast a const std::array<double,3> into a double&.
In order to fix this, you should have different parts of the hierarchy which define an operator which will work for all its children, like so (with non-pertainent stuff removed):
template <class T, class C>
struct foo
{
inline virtual T& operator[] ( unsigned n ) const = 0;
};
template <class T>
struct bar
: public foo<T,std::deque<T>>
{
inline virtual T& operator[] ( unsigned n ) const override
{ return const_cast<T&>( data()[n] ); }
};
template <class T, unsigned N>
struct baz
: public foo<T, std::deque<std::array<T,N>> >
{
inline virtual T& operator[] ( unsigned n ) const override
{ return const_cast<T&>( data()[n/N][n%N] ); }
};
This way if you have any other versions you want to add later, you can derive from bar or baz and not need to define the operator per-child.
How do I avoid implicit casting on non-constructing functions?
I have a function that takes an integer as a parameter,
but that function will also take characters, bools, and longs.
I believe it does this by implicitly casting them.
How can I avoid this so that the function only accepts parameters of a matching type, and will refuse to compile otherwise?
There is a keyword "explicit" but it does not work on non-constructing functions. :\
what do I do?
The following program compiles, although I'd like it not to:
#include <cstdlib>
//the function signature requires an int
void function(int i);
int main(){
int i{5};
function(i); //<- this is acceptable
char c{'a'};
function(c); //<- I would NOT like this to compile
return EXIT_SUCCESS;
}
void function(int i){return;}
*please be sure to point out any misuse of terminology and assumptions
Define function template which matches all other types:
void function(int); // this will be selected for int only
template <class T>
void function(T) = delete; // C++11
This is because non-template functions with direct matching are always considered first. Then the function template with direct match are considered - so never function<int> will be used. But for anything else, like char, function<char> will be used - and this gives your compilation errrors:
void function(int) {}
template <class T>
void function(T) = delete; // C++11
int main() {
function(1);
function(char(1)); // line 12
}
ERRORS:
prog.cpp: In function 'int main()':
prog.cpp:4:6: error: deleted function 'void function(T) [with T = char]'
prog.cpp:12:20: error: used here
This is C++03 way:
// because this ugly code will give you compilation error for all other types
class DeleteOverload
{
private:
DeleteOverload(void*);
};
template <class T>
void function(T a, DeleteOverload = 0);
void function(int a)
{}
You can't directly, because a char automatically gets promoted to int.
You can resort to a trick though: create a function that takes a char as parameter and don't implement it. It will compile, but you'll get a linker error:
void function(int i)
{
}
void function(char i);
//or, in C++11
void function(char i) = delete;
Calling the function with a char parameter will break the build.
See http://ideone.com/2SRdM
Terminology: non-construcing functions? Do you mean a function that is not a constructor?
8 years later (PRE-C++20, see edit):
The most modern solution, if you don't mind template functions -which you may mind-, is to use a templated function with std::enable_if and std::is_same.
Namely:
// Where we want to only take int
template <class T, std::enable_if_t<std::is_same_v<T,int>,bool> = false>
void func(T x) {
}
EDIT (c++20)
I've recently switched to c++20 and I believe that there is a better way. If your team or you don't use c++20, or are not familiar with the new concepts library, do not use this. This is much nicer and the intended method as outlines in the new c++20 standard, and by the writers of the new feature (read a papers written by Bjarne Stroustrup here.
template <class T>
requires std::same_as(T,int)
void func(T x) {
//...
}
Small Edit (different pattern for concepts)
The following is a much better way, because it explains your reason, to have an explicit int. If you are doing this frequently, and would like a good pattern, I would do the following:
template <class T>
concept explicit_int = std::same_as<T,int>;
template <explicit_int T>
void func(T x) {
}
Small edit 2 (the last I promise)
Also a way to accomplish this possibility:
template <class T>
concept explicit_int = std::same_as<T,int>;
void func(explicit_int auto x) {
}
Here's a general solution that causes an error at compile time if function is called with anything but an int
template <typename T>
struct is_int { static const bool value = false; };
template <>
struct is_int<int> { static const bool value = true; };
template <typename T>
void function(T i) {
static_assert(is_int<T>::value, "argument is not int");
return;
}
int main() {
int i = 5;
char c = 'a';
function(i);
//function(c);
return 0;
}
It works by allowing any type for the argument to function but using is_int as a type-level predicate. The generic implementation of is_int has a false value but the explicit specialization for the int type has value true so that the static assert guarantees that the argument has exactly type int otherwise there is a compile error.
Maybe you can use a struct to make the second function private:
#include <cstdlib>
struct NoCast {
static void function(int i);
private:
static void function(char c);
};
int main(){
int i(5);
NoCast::function(i); //<- this is acceptable
char c('a');
NoCast::function(c); //<- Error
return EXIT_SUCCESS;
}
void NoCast::function(int i){return;}
This won't compile:
prog.cpp: In function ‘int main()’:
prog.cpp:7: error: ‘static void NoCast::function(char)’ is private
prog.cpp:16: error: within this context
For C++14 (and I believe C++11), you can disable copy constructors by overloading rvalue-references as well:
Example:
Say you have a base Binding<C> class, where C is either the base Constraint class, or an inherited class. Say you are storing Binding<C> by value in a vector, and you pass a reference to the binding and you wish to ensure that you do not cause an implicit copy.
You may do so by deleting func(Binding<C>&& x) (per PiotrNycz's example) for rvalue-reference specific cases.
Snippet:
template<typename T>
void overload_info(const T& x) {
cout << "overload: " << "const " << name_trait<T>::name() << "&" << endl;
}
template<typename T>
void overload_info(T&& x) {
cout << "overload: " << name_trait<T>::name() << "&&" << endl;
}
template<typename T>
void disable_implicit_copy(T&& x) = delete;
template<typename T>
void disable_implicit_copy(const T& x) {
cout << "[valid] ";
overload_info<T>(x);
}
...
int main() {
Constraint c;
LinearConstraint lc(1);
Binding<Constraint> bc(&c, {});
Binding<LinearConstraint> blc(&lc, {});
CALL(overload_info<Binding<Constraint>>(bc));
CALL(overload_info<Binding<LinearConstraint>>(blc));
CALL(overload_info<Binding<Constraint>>(blc));
CALL(disable_implicit_copy<Binding<Constraint>>(bc));
// // Causes desired error
// CALL(disable_implicit_copy<Binding<Constraint>>(blc));
}
Output:
>>> overload_info(bc)
overload: T&&
>>> overload_info<Binding<Constraint>>(bc)
overload: const Binding<Constraint>&
>>> overload_info<Binding<LinearConstraint>>(blc)
overload: const Binding<LinearConstraint>&
>>> overload_info<Binding<Constraint>>(blc)
implicit copy: Binding<LinearConstraint> -> Binding<Constraint>
overload: Binding<Constraint>&&
>>> disable_implicit_copy<Binding<Constraint>>(bc)
[valid] overload: const Binding<Constraint>&
Error (with clang-3.9 in bazel, when offending line is uncommented):
cpp_quick/prevent_implicit_conversion.cc:116:8: error: call to deleted function 'disable_implicit_copy'
CALL(disable_implicit_copy<Binding<Constraint>>(blc));
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Full Source Code: prevent_implicit_conversion.cc
Well, I was going to answer this with the code below, but even though it works with Visual C++, in the sense of producing the desired compilation error, MinGW g++ 4.7.1 accepts it, and invokes the rvalue reference constructor!
I think it must be a compiler bug, but I could be wrong, so – anyone?
Anyway, here's the code, which may turn out to be a standard-compliant solution (or, it may turn out that that's a thinko on my part!):
#include <iostream>
#include <utility> // std::is_same, std::enable_if
using namespace std;
template< class Type >
struct Boxed
{
Type value;
template< class Arg >
Boxed(
Arg const& v,
typename enable_if< is_same< Type, Arg >::value, Arg >::type* = 0
)
: value( v )
{
wcout << "Generic!" << endl;
}
Boxed( Type&& v ): value( move( v ) )
{
wcout << "Rvalue!" << endl;
}
};
void function( Boxed< int > v ) {}
int main()
{
int i = 5;
function( i ); //<- this is acceptable
char c = 'a';
function( c ); //<- I would NOT like this to compile
}
I first tried PiotrNycz's approach (for C++03, which I'm forced to use for a project), then I tried to find a more general approach and came up with this ForcedType<T> template class.
template <typename T>
struct ForcedType {
ForcedType(T v): m_v(v) {}
operator T&() { return m_v; }
operator const T&() const { return m_v; }
private:
template <typename T2>
ForcedType(T2);
T m_v;
};
template <typename T>
struct ForcedType<const T&> {
ForcedType(const T& v): m_v(v) {}
operator const T&() const { return m_v; }
private:
template <typename T2>
ForcedType(const T2&);
const T& m_v;
};
template <typename T>
struct ForcedType<T&> {
ForcedType(T& v): m_v(v) {}
operator T&() { return m_v; }
operator const T&() const { return m_v; }
private:
template <typename T2>
ForcedType(T2&);
T& m_v;
};
If I'm not mistaken, those three specializations should cover all common use cases. I'm not sure if a specialization for rvalue-reference (on C++11 onwards) is actually needed or the by-value one suffices.
One would use it like this, in case of a function with 3 parameters whose 3rd parameter doesn't allow implicit conversions:
function(ParamType1 param1, ParamType2 param2, ForcedType<ParamType3> param3);