I'm attempting to overload some operators for an Enum class.
I get a compiler error saying it's unable to find the operator
In Enum.h
enum class SomeEnum : unsigned
{
Test0 = 0,
Test1 = (1 << 0),
Test2 = (1 << 1),
};
In Enum.cpp
#include "Enum.h"
#include <type_traits>
SomeEnum operator|(SomeEnum lhs, SomeEnum rhs)
{
return static_cast<SomeEnum > (
static_cast<std::underlying_type<SomeEnum >::type>(lhs) |
static_cast<std::underlying_type<SomeEnum >::type>(rhs)
);
}
in main.cpp
#include "Enum.h"
int main()
{
SomeEnum blah = SomeEnum::Test1 | SomeEnum::Test2;
}
The compiler spits out an error saying:
no match for 'operator|' (operand types are 'SomeEnum ' and 'SomeEnum ')
You need to add declaration of operator| to Enum.h file:
enum class SomeEnum : unsigned
{
Test0 = 0,
Test1 = (1 << 0),
Test2 = (1 << 1),
};
SomeEnum operator|(SomeEnum lhs, SomeEnum rhs); // added
Without this declaration in main.cpp after including Enum.h compiler can see only definition of SomeEnum, but it is not aware of presence operator| defined in Enum.cpp
Related
I just discovered that gcc and clang++, would let me use a const int for the underlying type of an enum. I wonder if that has any utility of if for all purposes it is the same as having an enum based on int.
I thought that may be it would make the enum instance not assignable, but it was not the case. (And to be honest, I thought it would not compile in the same way that you can't make a class derived from a const base type class C2 : const C1{})
Is there any use or subtle difference between enum : int and enum : const int? If no, why would the compiler allow it?
Example:
#include<iostream>
enum A : const int{ // is this the same as enum A : int ?
no = 0,
si
};
int main(){
A a;
a = si; // is asignable
a = no; // twice
std::cout << (int)a << std::endl; // prints '0'
return 0;
}
Funny that I can do this enum A : volatile int as well.
(Fortunately, I can't do this enum A : int& or enum A : int*.)
For completeness sake, here is the relevant standard quote (from C++11 up to latest draft):
[dcl.enum]#2 The enumeration type [...] The type-specifier-seq of an enum-base shall name an integral type; any cv-qualification is ignored.
where type-specifier-seq is the underlying type specification in the corresponding grammar production.
There seems to be no difference - the underlaying type for both is int. Here some example test program:
#include <iostream>
#include <type_traits>
enum e1 : int {};
enum e2: const int {};
int main() {
bool e1_type = std::is_same<
const int
,typename std::underlying_type<e1>::type
>::value;
bool e2_type = std::is_same<
const int
,typename std::underlying_type<e2>::type
>::value;
std::cout
<< "underlying type for 'e1' is " << (e1_type?"const":"non-const") << '\n'
<< "underlying type for 'e2' is " << (e2_type?"const":"non-const") << '\n';
}
https://wandbox.org/permlink/dXLDe80zKhSxglcl
Can't resolve this instance of calling std::lower_bound from std::async. Example:
#include <vector>
#include <algorithm>
#include <future>
#include <iostream>
int main() {
std::vector<int> v = {1,3,4,6,7};
auto res = std::async(std::launch::async, std::lower_bound, v.begin(), v.end(), 4);
std::cout << *res.get() << std::endl;
return 0;
}
Compiler output makes it look like it doesn't realize std::launch::async is a launch policy and it should use the async call with the launch policy but I could be wrong.
test.cpp:8:84: error: no matching function for call to ‘async(std::launch, <unresolved overloaded function type>, std::vector<int>::iterator, std::vector<int>::iterator, int)’
res = std::async(std::launch::async, std::lower_bound, v.begin(), v.end(), 3);
^
In file included from test.cpp:3:0:
/usr/include/c++/6/future:1709:5: note: candidate: template<class _Fn, class ... _Args> std::future<typename std::result_of<typename std::decay<_Tp>::type(typename std::decay<_BoundArgs>::type ...)>::type> std::async(std::launch, _Fn&&, _Args&& ...)
async(launch __policy, _Fn&& __fn, _Args&&... __args)
^~~~~
/usr/include/c++/6/future:1709:5: note: template argument deduction/substitution failed:
test.cpp:8:84: note: couldn't deduce template parameter ‘_Fn’
res = std::async(std::launch::async, std::lower_bound, v.begin(), v.end(), 3);
^
In file included from test.cpp:3:0:
/usr/include/c++/6/future:1739:5: note: candidate: template<class _Fn, class ... _Args> std::future<typename std::result_of<typename std::decay<_Tp>::type(typename std::decay<_BoundArgs>::type ...)>::type> std::async(_Fn&&, _Args&& ...)
async(_Fn&& __fn, _Args&&... __args)
^~~~~
/usr/include/c++/6/future:1739:5: note: template argument deduction/substitution failed:
/usr/include/c++/6/future: In substitution of ‘template<class _Fn, class ... _Args> std::future<typename std::result_of<typename std::decay<_Tp>::type(typename std::decay<_BoundArgs>::type ...)>::type> std::async(_Fn&&, _Args&& ...) [with _Fn = std::launch; _Args = {}]’:
test.cpp:8:84: required from here
/usr/include/c++/6/future:1739:5: error: no type named ‘type’ in ‘class std::result_of<std::launch()>’
std::lower_bound is a function template, you have to explicitly specify its arguments to be able to pass it around:
int main() {
using V = std::vector<int>;
V v = {1,3,4,6,7};
auto res = std::async(std::launch::async, std::lower_bound<V::iterator, int>, v.begin(), v.end(), 4);
std::cout << *res.get() << std::endl;
return 0;
}
Ben Deane mentions the throw trick, which ensures a link error when a constexpr function is used in a non-constexpr context.
Here is my take:
#include <iostream>
struct Exc;
constexpr int foo( int a )
{
if( a == 42 )
{
throw Exc{};
}
return 666;
}
int main()
{
constexpr auto ret = foo(43);
std::cout << ret << "\n";
return ret;
}
But I couldn't make it work (clang++ 3.8.1-23 and g++ 6.3.0):
$ clang++ -std=c++14 main.cpp
main.cpp:9:15: error: invalid use of incomplete type 'ExcBase'
throw ExcBase{};
^~~~~~~~~
main.cpp:3:8: note: forward declaration of 'ExcBase'
struct ExcBase;
^
1 error generated.
A comment in this thread suggests another trick:
#include <iostream>
constexpr int foo( int a )
{
if( a == 42 )
{
(void)reinterpret_cast<int>(a);
}
return 666;
}
int main()
{
constexpr auto ret = foo(43);
std::cout << ret << "\n";
return ret;
}
Which works: no errors or warnings; when the invocation is replaced with foo(42), clang returns:
$ clang++ -std=c++14 main.cpp
main.cpp:19:20: error: constexpr variable 'ret' must be initialized by a constant expression
constexpr auto ret = foo(42);
^ ~~~~~~~
main.cpp:10:15: note: reinterpret_cast is not allowed in a constant expression
(void)reinterpret_cast<int>(a);
^
main.cpp:19:26: note: in call to 'foo(42)'
constexpr auto ret = foo(42);
^
1 error generated.
Which is great. But gcc compiles the code happily in both cases. And now the question. How can a constexpr function be written in such a way, that it cannot be used in non-constexpr environments?
The problem is you actually instantiate (call constructor) a struct which is of incomplete type. This trick you talk about requires any symbol which will not be found at link time. So instead of struct you may use int:
http://coliru.stacked-crooked.com/a/3df5207827c8888c
#include <iostream>
extern int Exc;
constexpr int foo( int a )
{
if( a == 42 )
{
throw Exc;
}
return 666;
}
int main()
{
// Compiles
constexpr auto ret = foo(43);
std::cout << ret << "\n";
// This will show linker error as expected:
// /tmp/ccQfT6hd.o: In function `main':
// main.cpp:(.text.startup+0x4c): undefined reference to `Exc'
// collect2: error: ld returned 1 exit status
int nn;
std::cin >> nn;
auto ret2 = foo(nn);
return ret;
}
Below is the templatized version of insertion sort which results in compilation errors to perform insertion sort in place without any extra space.
#include <vector>
#include <iostream>
#include <algorithm>
#include <iterator>
using namespace std;
template <typename T>
insertSort(T start, T end)
{
typename std::vector<typename std::iterator_traits<T>::value_type> TmpVec;
TmpVec tmp(std::make_move_iterator(start), std::make_move_iterator(end));
TmpVec::iterator begin = std::begin(tmp);
TmpVec::iterator end = std::end(tmp);
for(TmpVec::iterator i = begin; i != end; i++)
{
typename std::iterator_traits<T>::value_type value = *i;
TmpVec::iterator pos = i;
while (pos > start && *(pos-1) > value)
{
*pos = std::move(*(pos-1));
--pos;
}
*pos = value;
}
}
int main(int argc, char** argv) {
std::vector<double> arr = {1,5,3,2,6,3,9,8};
insertSort<double>(arr.begin(), arr.end());
for(int i=0; i<arr.size(); i++)
{
std::cout << arr[i] << " ";
}
return 0;
}
I am compiling this with the following compilation line.
g++ -std=c++11 -c -g -MMD -MP -MF "build/Debug/MinGW-Windows/main.o.d" -o build/Debug/MinGW-Windows/main.o main.cpp
This yields the following errors.
main.cpp: In function 'int insertSort(T, T)':
main.cpp:21:12: error: expected ';' before 'tmp'
TmpVec tmp(std::make_move_iterator(start), std::make_move_iterator(end));
^
main.cpp:22:5: error: 'TmpVec' is not a class, namespace, or enumeration
TmpVec::iterator begin = std::begin(tmp);
^
main.cpp:23:5: error: 'TmpVec' is not a class, namespace, or enumeration
TmpVec::iterator end = std::end(tmp);
^
main.cpp:24:9: error: 'TmpVec' is not a class, namespace, or enumeration
for(TmpVec::iterator i = begin; i != end; i++)
^
main.cpp:24:37: error: 'i' was not declared in this scope
for(TmpVec::iterator i = begin; i != end; i++)
^
main.cpp:27:9: error: 'TmpVec' is not a class, namespace, or enumeration
TmpVec::iterator pos = i;
^
main.cpp:28:16: error: 'pos' was not declared in this scope
while (pos > start && *(pos-1) > value)
^
main.cpp:33:10: error: 'pos' was not declared in this scope
*pos = value;
^
main.cpp: In function 'int main(int, char**)':
main.cpp:40:46: error: no matching function for call to 'insertSort(std::vector<double>::iterator, std::vector<double>::iterator)'
insertSort<double>(arr.begin(), arr.end());
^
main.cpp:40:46: note: candidate is:
main.cpp:18:1: note: template<class T> int insertSort(T, T)
insertSort(T start, T end)
^
main.cpp:18:1: note: template argument deduction/substitution failed:
main.cpp:40:46: note: cannot convert 'arr.std::vector<_Tp, _Alloc>::begin<double, std::allocator<double> >()' (type 'std::vector<double>::iterator {aka __gnu_cxx::__normal_iterator<double*, std::vector<double> >}') to type 'double'
insertSort<double>(arr.begin(), arr.end());
Kindly help in solving the above issue.
typename std::vector<typename std::iterator_traits<T>::value_type> TmpVec;
this states std::vector<typename std::iterator_traits<T>::value_type> is a typename. A compiler should issue a warning/error, because the typename is redundant.
It then declares a variable TmpVec of that type.
Every use after that uses TmpVec as if it was a type, not a variable.
You probably want
typedef std::vector<typename std::iterator_traits<T>::value_type> TmpVec;
I'd also advise
using tmp_iterator = typename TmpVec::iterator;
and using tmp_iterator as a type instead of TmpVec::iterator.
I'm trying to set up a parser which, given a value, can assign it to a certain element of a vector, but I'm not entirely sure how to implement it.
Let's say the following piece of code parses the string (0){**+*+}. It should increment bar.a[0] once for every +, and bar.b[0] once for every *. The issue I'm encountering is that I'm not sure how to get a reference to a vector's element using _a:
#include <boost/spirit/include/qi.hpp>
#include <boost/fusion/include/adapt_struct.hpp>
#include <boost/spirit/include/phoenix_fusion.hpp>
#include <boost/spirit/include/phoenix_operator.hpp>
#include <vector>
//The struct containing the vector.
struct testStruct {
std::vector<int> a, b;
};
BOOST_FUSION_ADAPT_STRUCT (
testStruct,
(std::vector<int>, a)
(std::vector<int>, b)
)
namespace qi = boost::spirit::qi;
namespace phoenix = boost::phoenix;
namespace ascii = boost::spirit::ascii;
template<typename Iterator>
struct foo : qi::grammar<Iterator, testStruct(), qi::locals<unsigned>, ascii::space_type> {
foo() : foo::base_type(start) {
using namespace qi::labels;
using qi::eps;
using qi::lit;
using qi::uint_;
using phoenix::at_c;
start = lit('(')
>> uint_ [_a = _1]
>> ')'
>> '{'
>> starsOrPlus(
at_c<_a>(at_c<0>(_val)), //This is where I'm not sure what to do.
at_c<_a>(at_c<1>(_val))
)
>> '}'
;
starsOrPlus = eps [_r1 = 0]
[_r2 = 0]
>> (
* (
(
+lit('+') [_r1 += 1]
)
^ (
+lit('*') [_r2 += 1]
)
)
)
;
}
qi::rule<Iterator, testStruct(), qi::locals<unsigned>, ascii::space_type> start;
//Parses stars and pluses. Sets the first uint8_t to the number of *, and the
//second to the number of +.
qi::rule<Iterator, void(int&, int&), ascii::space_type> starsOrPlus;
};
//Main program
int main() {
std::string testString = "(2){**++*+}";
typedef foo<std::string::const_iterator> foo;
foo grammar;
testStruct bar;
std::string::const_iterator iter = testString.begin();
std::string::const_iterator end = testString.end();
bool parsed = phrase_parse(iter, end, grammar, ascii::space, bar);
if (parsed) {
//Do something with the data...
}
return 0;
}
This fails to compile with the following errors:
main.cpp||In constructor 'foo<Iterator>::foo()':|
main.cpp|36|error: 'boost::spirit::_a' cannot appear in a constant-expression|
main.cpp|36|error: no matching function for call to 'at_c(boost::phoenix::actor<boost::phoenix::composite<boost::phoenix::at_eval<0>, boost::fusion::vector<boost::spirit::attribute<0>, boost::fusion::void_, boost::fusion::void_, boost::fusion::void_, boost::fusion::void_, boost::fusion::void_, boost::fusion::void_, boost::fusion::void_, boost::fusion::void_, boost::fusion::void_> > >&)'|
main.cpp|37|error: 'boost::spirit::_a' cannot appear in a constant-expression|
main.cpp|37|error: no matching function for call to 'at_c(boost::phoenix::actor<boost::phoenix::composite<boost::phoenix::at_eval<1>, boost::fusion::vector<boost::spirit::attribute<0>, boost::fusion::void_, boost::fusion::void_, boost::fusion::void_, boost::fusion::void_, boost::fusion::void_, boost::fusion::void_, boost::fusion::void_, boost::fusion::void_, boost::fusion::void_> > >&)'|
So, clearly, I can't use a placeholder value within at_c. I'm also aware that, even if I could, there would also be the issue of re-sizing the vector if the given position is out of range.
How would I implement something like this? Am I just going about this entirely the wrong way?
This should get you started:
#include <vector>
#include <string>
#include <iostream>
#include <boost/fusion/include/adapt_struct.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix.hpp>
#include <boost/spirit/include/phoenix_fusion.hpp>
struct testStruct
{
std::vector<int> a, b;
};
BOOST_FUSION_ADAPT_STRUCT
(
testStruct,
(std::vector<int>, a)
(std::vector<int>, b)
)
namespace bp = boost::phoenix;
namespace bs = boost::spirit;
namespace bsq = bs::qi;
template<typename Iterator>
struct foo : bsq::grammar<Iterator, testStruct(), bsq::locals<unsigned> >
{
foo() : foo::base_type(start)
{
using namespace bs::labels;
using bp::at_c;
using bp::resize;
using bs::lit;
using bs::uint_;
start
= '('
>> uint_
[
_a = _1,
resize(at_c<0>(_val), _1 + 1),
resize(at_c<1>(_val), _1 + 1)
]
>> "){"
>> starsOrPlus(at_c<0>(_val)[_a], at_c<1>(_val)[_a])
>> '}'
;
starsOrPlus
= *(
lit('+')[_r1 += 1]
| lit('*')[_r2 += 1]
)
;
}
bsq::rule<Iterator, testStruct(), bsq::locals<unsigned> > start;
bsq::rule<Iterator, void(int&, int&)> starsOrPlus;
};
void printvec(std::vector<int> const& vec)
{
bool first = true;
for (std::vector<int>::const_iterator it = vec.begin(), it_end = vec.end();
it != it_end;
++it)
{
if (first)
first = false;
else
std::cout << ", ";
std::cout << *it;
}
}
int main()
{
foo<std::string::const_iterator> grammar;
testStruct bar;
std::string const input = "(2){**++*}";
std::string::const_iterator first = input.begin(), last = input.end();
if (bsq::parse(first, last, grammar, bar) && first == last)
{
std::cout << "bar.a: ";
printvec(bar.a);
std::cout << "\nbar.b: ";
printvec(bar.b);
std::cout << '\n';
}
else
std::cout << "parse failed\n";
}
The notable changes here are:
The vectors inside of testStruct must be resized to a size sufficient for the desired index to be valid
operator[] is used instead of boost::phoenix::at_c to access the index of a vector, just as one would in "normal" code
Note that I took out the skip parser to simplify things (and because it didn't appear to be necessary); add it back if you need to -- it had no real relevance here.