I try to extend the boost::dynamic_bitset class with some functionality I need, such as counting bits after an AND operation, etc. Also I need access to the private members (m_num_bits, etc) because I want to be able to "override" the set() method to ensure the bitset's capacity with the resize() fct, if the pos of the bit to set is greater then the current bitset capacity. If I use the native set() fct it throughs an assertion error in that case (because the set() method does not resize in such case)
I am not very experienced with templates, also I am just getting back into C++ since a few weeks, it's a bit rusty, maybe somebody can help me out.
I started doing this:
template <typename Block, typename Allocator>
class ExtendedBitSet : public boost::dynamic_bitset<Block, Allocator> {
typedef boost::dynamic_bitset<Block, Allocator> super;
public:
void set(std::size_t pos) {
if (pos > super::size())
super::resize(pos);
set(pos);
}
bool get(std::size_t pos) const {
return super::test(pos);
}
};
// ...
ExtendedBitSet<> * bs = new ExtendedBitSet<>(128);
bs->set(33);
// ...
std::wcout << "Bit 48 is " << ((bs->get(48) == true) ? "true" : "false") << std::endl;
// ...
delete bs;
Ofcourse this is not compiling, the error is:
dynamic_bitset.cpp: In function ‘int main(int, char**)’:
dynamic_bitset.cpp:50: error: wrong number of template arguments (0, should be 2)
dynamic_bitset.cpp:7: error: provided for ‘template<class T, class Allocator> class ExtendedBitSet’
dynamic_bitset.cpp:50: error: invalid type in declaration before ‘=’ token
dynamic_bitset.cpp:50: error: wrong number of template arguments (0, should be 2)
dynamic_bitset.cpp:7: error: provided for ‘template<class T, class Allocator> class ExtendedBitSet’
dynamic_bitset.cpp:51: error: request for member ‘set’ in ‘* bs’, which is of non-class type ‘int’
..
dynamic_bitset.cpp:57: error: request for member ‘get’ in ‘* bs’, which is of non-class type ‘int’
Can somebody give a hint how to get that running? Also is there maybe a better way than deriving from the dynamic_bitset class or is this OK to do?
Any help is greatly appreciated.
Your ExtendedBitSet<> has no default parameters for the template type parameters and your code is trying to instantiate it without specifying them explicitly. Try using ExtendedBitSet<unsigned, std::allocator<unsigned> > bs instead.
Related
Sorry for the generic title, but I'm unable to focus the problem.
I have a templatized class method that accept an argument pack and provides a new type in return, to hide the details of the implementation. More specifically, the class handles SQLite queries, and the method calls sqlite3_prepare() to prepare the statement before executing the query.
class Table {
...
template <typename ...Ts>
class PreparedStatement { ... };
template <typename ...Ts>
PreparedStatement<Ts...> prepare(std::tuple<Ts...> tuple) {
// do something
return PreparedStatement<Ts...> ( ... );
}
That works well with "normal" types, but the problem occurs when the arguments are declared const:
const Field<int> fld = createField<int>("name");
...
PreparedStatement<decltype(fld)> s = prepare(make_tuple(fld));
The error is the following:
no match for 'operator =' (operand types are PreparedStatenent<const Field<int>> and PreparedStatement<Field<int>>
I suspect the issue is in my declaration of the function, is there a way to fix this issue and make the function more "elegant" ?
NOTE: I know I can fix the issue by manually declare the s variable, but my doubts are on how the method was implemented.
As Many Asked, here's an example:
#include <tuple>
template <typename T>
struct Field {
};
class Table {
public:
template <typename ...Ts>
class PreparedStatement {
public:
PreparedStatement() {};
};
template <typename ...Ts>
PreparedStatement<Ts...> prepare(std::tuple<Ts...> tuple) {
// do something
return PreparedStatement<Ts...> ( );
}
};
int main()
{
Field<int> fld;
Table t;
Table::PreparedStatement<decltype(fld)> p;
p = t.prepare(std::make_tuple(fld));
// here comes the problem
const Field<int> f2;
Table::PreparedStatement<decltype(f2)> p2;
p2 = t.prepare(std::make_tuple(f2));
return 0;
}
and here's the compiler output
main.cpp: In function 'int main()': main.cpp:35:39: error: no match
for 'operator=' (operand types are 'Table::PreparedStatement >' and 'Table::PreparedStatement >')
p2 = t.prepare(std::make_tuple(f2));
^ main.cpp:10:10: note: candidate: constexpr Table::PreparedStatement >&
Table::PreparedStatement >::operator=(const
Table::PreparedStatement >&)
class PreparedStatement {
^~~~~~~~~~~~~~~~~ main.cpp:10:10: note: no known conversion for argument 1 from 'Table::PreparedStatement >'
to 'const Table::PreparedStatement >&'
main.cpp:10:10: note: candidate: constexpr
Table::PreparedStatement >&
Table::PreparedStatement
::operator=(Table::PreparedStatement >&&) main.cpp:10:10: note: no known conversion for argument 1 from
'Table::PreparedStatement >' to
'Table::PreparedStatement >&&'
UPDATE
As many noted, I could use auto to deduce the type, but in some condition auto cannot practically be used. One is, for example, if I need to declare the statement in the Class Context.
So suppose auto is forbidden for some reason. Isn't any other solution available? See the updated code above.
cppreference.com for make_tuple tells us:
template< class... Types >
tuple<VTypes...> make_tuple( Types&&... args );
For each Ti in Types..., the corresponding type Vi in Vtypes... is
std::decay<Ti>::type unless application of std::decay results in
std::reference_wrapper<X> for some type X, in which case the deduced
type is X&.
While std::decay, among other things, removes cv-qualifiers. So your type will be no PreparedStatement<const Field<int>>, but PreparedStatement<Field<int>>.
You can use auto, as manni66 proposed, to avoid such problems.
auto s = prepare(make_tuple(fld));
I could use auto to deduce the type, but in some condition auto cannot practically be used. One is, for example, if I need to declare the statement in the Class Context. So suppose auto is forbidden for some reason. Isn't any other solution available? See the updated code above.
Instead of auto, you can use a decltype expression that take in count the value returned by prepare.
I mean... instead of
Table::PreparedStatement<decltype(f2)> p2;
you can try with
decltype(t.prepare(std::make_tuple(f2))) p2;
or
decltype(std::declval<Table>().prepare(
std::make_tuple(std::declval<Field<int>>()))) p2;
I suppose you can use a similar decltype() also to declare members of your classes.
I have created a hasher class for a custom type I'm using, but it has a constructor that takes an argument. I can't figure out the syntax to use this in an unordered_set.
class Hasher {
unsigned arg;
public:
Hasher(unsigned a) : arg(a) {}
size_t operator()(const MyType& t) const {
return calculate_hash(arg, t);
}
}
int main() {
unordered_set<MyType, Hasher(2)> myset; // compilation error
}
The error message:
In file included from Tetrahedron.cc:5:
./Triangulation.h:52:29: error: template argument for template type parameter must be a type
unordered_set<TetraFace,FaceHasher(2)> faces2;
^~~~~~~~~~~~~
/bin/../lib/gcc/x86_64-redhat-linux/6.3.1/../../../../include/c++/6.3.1/bits/unordered_set.h:90:11: note: template parameter is declared here
class _Hash = hash<_Value>,
^
I also tried
unordered_set<MyType, Hasher> myset(Hasher(2));
but I still get an error:
In file included from Tetrahedron.cc:5:
./Triangulation.h:52:59: error: expected ')'
unordered_set<TetraFace,FaceHasher> faces2(FaceHasher(2));
^
./Triangulation.h:52:58: note: to match this '('
unordered_set<TetraFace,FaceHasher> faces2(FaceHasher(2));
^
You're getting a compile error there because you're trying to pass an object (i.e. instance) of type Hasher as a template argument.
Like your error describes: template argument for template type parameter must be a type
It's expecting a type, and you're passing in a value.
Parameterize the arg at the type level.
template<unsigned A>
class Hasher {
unsigned arg = A;
public:
size_t operator()(const int& t) const {
std::cout << arg << std::endl;
return 0;
}
};
int main() {
std::unordered_set<int, Hasher<2>> myset;
myset.insert(5); // prints 2
std::unordered_set<int, Hasher<3>> myset2;
myset2.insert(3); // prints 3
}
Unfortunately it is not possible to construct a std::unorderd_set with just the hash object. All of the constructors that take the hash object have a parameter before it for bucket_count. You would need to specify the value for it like
unordered_set<MyType, Hasher> myset(some_bucket_count_value, Hasher(2));
If you do not want to do that then you have to make Hasher default constructable.
Also not that
return calculate_hash(arg);
Is not going to work as you will always hash arg no matter what MyType you pass. You need to be hashing the MyType object for the std::unordered_set to really work.
I'm writing a template class with a method that performs some bitwise operations, so I want to limit the type in the case this method is used within is_integral. I took the simple example here and modified a bit as follows:
#include <iostream>
#include <type_traits>
template <typename T>
class A
{
public:
A();
T foo(T i) {
static_assert(std::is_integral<T>::value, "Integer required.");
return (i & 2);
}
private:
T x;
};
int main() {
A<double> a;
std::cout << a.foo(3) << std::endl;
return 0;
}
However, compiler gives me 2 compile errors at static_assert():
static_assert failed "Integer required."
and at return (i & 2);:
invalid operands to binary expression ('double' and 'double')
My question is, if it will show the error at line return (i & 2); anyway, using type_traits to check for type here seems useless? And, is there anyway to throw the error to console output when it runs, instead of making it unable to be compiled?
My question is, if it will show the error at line return (i & 2); anyway, using type_traits to check for type here seems useless?
It's true that it's unfortunate that you get subsequent compile errors anyway, but which compile error do you find more readable?
"Integer required."
invalid operands to binary expression (double and double)
I know what I did wrong about the first one - I have A<double> but foo() requires an integer. No idea about the second. Am I misusing your class template or does it have a bug?
And, is there anyway to throw the error to console output when it runs, instead of making it unable to be compiled?
You want it to be a compile error. Catching errors at compile time is a lot better than catching errors at compile time.
Compiler is trying to report as many errors as it can. static_assert reports an error, but there is another error as well (using double argument for &) so it also is reported.
If you want to limit output to one error, you should have two sfinae-enabled overloads and have a second one (for anything but integrals) consist of a single static_assert.
As for your last question, the whole purpose of doing static_assert is to trigger errors at compile time, not runtime.
Here's another way to achieve the same thing. You may or may not prefer the error messages:
#include <iostream>
#include <type_traits>
template <typename T, typename = std::enable_if_t<std::is_integral<T>::value>>
class A
{
public:
A();
T foo(T i) {
return (i & 2);
}
private:
T x;
};
int main() {
A<double> a;
std::cout << a.foo(3) << std::endl;
return 0;
}
sample errors:
In file included from /opt/gcc-5.3.0/include/c++/5.3.0/bits/move.h:57:0,
from /opt/gcc-5.3.0/include/c++/5.3.0/bits/stl_pair.h:59,
from /opt/gcc-5.3.0/include/c++/5.3.0/bits/stl_algobase.h:64,
from /opt/gcc-5.3.0/include/c++/5.3.0/bits/char_traits.h:39,
from /opt/gcc-5.3.0/include/c++/5.3.0/ios:40,
from /opt/gcc-5.3.0/include/c++/5.3.0/ostream:38,
from /opt/gcc-5.3.0/include/c++/5.3.0/iostream:39,
from /tmp/gcc-explorer-compiler11636-75-1ve7gbt/example.cpp:1:
/opt/gcc-5.3.0/include/c++/5.3.0/type_traits: In substitution of 'template<bool _Cond, class _Tp> using enable_if_t = typename std::enable_if::type [with bool _Cond = std::integral_constant<bool, false>::value; _Tp = void]':
19 : required from here
/opt/gcc-5.3.0/include/c++/5.3.0/type_traits:2388:61: error: no type named 'type' in 'struct std::enable_if<false, void>'
using enable_if_t = typename enable_if<_Cond, _Tp>::type;
^
/tmp/gcc-explorer-compiler11636-75-1ve7gbt/example.cpp: In function 'int main()':
19 : error: template argument 2 is invalid
A<double> a;
^
20 : error: request for member 'foo' in 'a', which is of non-class type 'int'
std::cout << a.foo(3) << std::endl;
^
Compilation failed
I've got some template code that I'm modifying and I've run into an odd error that I can't work around. I was able to recreate the problem with the below simpler (but admittedly pointless) code snippet:
struct Widget
{
};
template <typename A>
class Foo
{
public:
template <int numA>
inline bool funcCall()
{
return numA > 0;
}
inline bool funcCallNoTemplate()
{
return false;
}
};
template <typename B>
class Bar : public Foo<B>
{
public:
// doesn't work
bool concrete()
{
return Foo<B>::funcCall<5>();
}
// works fine
bool other()
{
return Foo<B>::funcCallNoTemplate();
}
};
int main()
{
Bar<Widget> b;
b.concrete();
b.other();
return 0;
}
The error I get with GCC 4.7 is the following (line 30 is the body of Bar::concrete):
example.cxx: In member function ‘bool Bar<B>::concrete()’:
example.cxx:30: error: expected primary-expression before ‘)’ token
example.cxx: In member function ‘bool Bar<B>::concrete() [with B = Widget]’:
example.cxx:43: instantiated from here
example.cxx:30: error: invalid operands of types ‘<unresolved overloaded function type>’ and ‘int’ to binary ‘operator<’
It seems like the compiler can't even parse this correctly, am I missing something here that makes that line completely bogus?
It seems like the compiler can't even parse this correctly, am I missing something here that makes that line completely bogus?
Yes. You need to use the template disambiguator:
return Foo<B>::template funcCall<5>();
// ^^^^^^^^
This way you will tell the compiler to parse the dependent name funcCall as the name of a member function template, and the subsequent angular brackets as delimiters for the corresponding template arguments.
Without it, funcCall will be parsed as the name of a data member, while < and > will be parsed as less-than and greater-than, respectively.
I have a template class where I want to use objects of that class (along with the parameterized type) inside a map. So far this is the solution that I've been able to arrive at:
class IStatMsg;
template <typename T>
class ITier
{
public:
// Methods
ITier(TierType oType) : o_Type(oType){};
virtual ~ITier(){};
typename ITier<T> ParamITier; // line 60
ITier* Get(T oKey)
{
std::map<T, ParamITier*>::iterator it = map_Tiers.find(oKey); // line 64
if (it != map_Tiers.end())
return it->second;
return NULL;
}
void Set(T oKey, ITier* pTier)
{
map_Tiers.insert(pair<T, ParamITier*>(oKey, pTier)); // line 74
}
TierType GetType() { return o_Type; }
protected:
// Methods
// Attributes
std::map<T, ParamITier*> map_Tiers; // line 83
TierType o_Type;
private:
// Methods
// Attributes
};
But when I try to compile this code I get a long list of errors:
/home/gayanm/street/src/QueryServer_NEW/ITier.h:60:
error: expected nested-name-specifier
/home/gayanm/street/src/QueryServer_NEW/ITier.h:60:
error: ITier<T>' specified as
declarator-id
/home/gayanm/street/src/QueryServer_NEW/ITier.h:60:
error: perhaps you wantITier'
for a constructor
/home/gayanm/street/src/QueryServer_NEW/ITier.h:60:
error: two or more data types in
declaration of ITier<T>'
/home/gayanm/street/src/QueryServer_NEW/ITier.h:60:
error: expected;' before
"ParamITier"
/home/gayanm/street/src/QueryServer_NEW/ITier.h:83:
error: ParamITier' was not declared
in this scope
/home/gayanm/street/src/QueryServer_NEW/ITier.h:83:
error: template argument 2 is invalid
/home/gayanm/street/src/QueryServer_NEW/ITier.h:83:
error: template argument 4 is invalid
/home/gayanm/street/src/QueryServer_NEW/ITier.h:83:
error: ISO C++ forbids declaration of
map_Tiers' with no type
/home/gayanm/street/src/QueryServer_NEW/ITier.h:
In member function ITier<T>*
ITier<T>::Get(T)':
/home/gayanm/street/src/QueryServer_NEW/ITier.h:64:
error:ParamITier' undeclared (first
use this function)
/home/gayanm/street/src/QueryServer_NEW/ITier.h:64:
error: (Each undeclared identifier is
reported only once for each function
it appears in.)
/home/gayanm/street/src/QueryServer_NEW/ITier.h:64:
error: template argument 2 is invalid
/home/gayanm/street/src/QueryServer_NEW/ITier.h:64:
error: template argument 4 is invalid
/home/gayanm/street/src/QueryServer_NEW/ITier.h:64:
error: expected ;' before '::' token
/home/gayanm/street/src/QueryServer_NEW/ITier.h:66:
error:it' undeclared (first use this
function)
/home/gayanm/street/src/QueryServer_NEW/ITier.h:66:
error: request for member end' in
((ITier)this)->ITier::map_Tiers',
which is of non-class type int'
/home/gayanm/street/src/QueryServer_NEW/ITier.h:
In member functionvoid
ITier::Set(T, ITier)':
/home/gayanm/street/src/QueryServer_NEW/ITier.h:74:
error: request for member insert' in
((ITier*)this)->ITier::map_Tiers',
which is of non-class type int'
/home/gayanm/street/src/QueryServer_NEW/ITier.h:74:
error:pair' undeclared (first use
this function)
/home/gayanm/street/src/QueryServer_NEW/ITier.h:74:
error: expected primary-expression
before ',' token
/home/gayanm/street/src/QueryServer_NEW/ITier.h:74:
error: ParamITier' undeclared (first
use this function)
/home/gayanm/street/src/QueryServer_NEW/ITier.h:74:
error: expected primary-expression
before '>' token
/home/gayanm/street/src/QueryServer_NEW/ITier.h:
At global scope:
/home/gayanm/street/src/QueryServer_NEW/ITier.h:93:
error: baseITier' with
only non-default constructor in class
without a constructor
/home/gayanm/street/src/QueryServer_NEW/ITier.h:109:
error: expected class-name before '{'
token
Could you please point out how to fix these?
Thank You.
Line 60 does not access a depending name. What you use is ITier<T> of which the compiler knows it's a template given an argument. Instead of typename you want to use typedef ;)
Line 64 does access the depending name iterator which is a type-name, so you have to put typename before std::map. I put the two disambiguations, template and typename on this answer: Disambiguations of dependent names.
Line 74 would be right, if you fix the bug in Line 60, as far as i can see.
Line 83 is alright in itself as far as i can see.
Also, I would recommend that you pass const T& to the functions instead of T, since you cannot be sure (it's a template parameter!) that it'll be a "cheap" copy.
Thanks a lot litb. I was able to fix my code with the guidelines you provided.
class IStatMsg;
template <typename T>
class ITier
{
public:
// Methods
ITier(){};
ITier(TierType oType) : o_Type(oType){};
virtual ~ITier(){};
//typename ITier<T> ParamITier;
ITier<T>* Get(T oKey)
{
typename std::map<T, ITier<T>*>::iterator it = map_Tiers.find(oKey);
if (it != map_Tiers.end())
return it->second;
return NULL;
}
void Set(T oKey, ITier<T>* pTier)
{
map_Tiers.insert(std::pair<T, ITier<T>*>(oKey, pTier));
}
TierType GetType() { return o_Type; }
protected:
// Methods
// Attributes
std::map<T, ITier<T>*> map_Tiers;
TierType o_Type;
private:
// Methods
// Attributes
};