I have an enum like this:
namespace api {
enum Operation {
INSERT =1,
UPDATE =2,
DELETE =3,
};
const Operation Operation_MIN = INSERT;
const Operation Operation_MAX = DELETE;
} // api
and I want to write some tests that use it:
#include "gtest.h"
class FWTest : public ::testing::Test {};
class FWTestPar : public FWTest, public ::testing::WithParamInterface<api::Operation>
{};
INSTANTIATE_TEST_CASE_P(Piping, FWTestPar, ::testing::Range(
api::Operation_MIN, api::Operation_MAX+1)
);
To be able to increment enums, I wrote this operator:
template <typename E>
constexpr typename std::enable_if<std::is_enum<E>::value, E>::type
operator+(E val, int step)
{
return static_cast<E>(static_cast<int>(val) + step);
}
This compiles fine with G++ from 4.8 to 6.2, but clang refuses to find operator+
:
clang++ -g -std=c++14 -Wall -pedantic -Wextra -Wformat=2 -I ~/workspace/zarquon -o "enum_inc_real" "enum_inc_real.cc" (in directory: /tmp)
In file included from enum_inc_real.cc:1:
third_party/gmock/gtest/gtest.h:10250:34: error: assigning to 'api::Operation' from incompatible type 'int'
for (T i = begin; i < end; i = i + step)
^ ~~~~~~~~
third_party/gmock/gtest/gtest.h:10191:33: note: in instantiation of member function 'testing::internal::RangeGenerator<api::Operation, int>::CalculateEndIndex' requested here
step_(step), end_index_(CalculateEndIndex(begin, end, step)) {}
^
third_party/gmock/gtest/gtest.h:15815:11: note: in instantiation of member function 'testing::internal::RangeGenerator<api::Operation, int>::RangeGenerator' requested here
new internal::RangeGenerator<T, IncrementT>(start, end, step));
^
third_party/gmock/gtest/gtest.h:15820:10: note: in instantiation of function template specialization 'testing::Range<api::Operation, int>' requested here
return Range(start, end, 1);
^
enum_inc_real.cc:34:55: note: in instantiation of function template specialization 'testing::Range<api::Operation>' requested here
INSTANTIATE_TEST_CASE_P(Piping, FWTestPar, ::testing::Range(
^
In file included from enum_inc_real.cc:1:
third_party/gmock/gtest/gtest.h:10213:14: error: assigning to 'api::Operation' from incompatible type 'int'
value_ = value_ + step_;
^ ~~~~~~~~~~~~~~
third_party/gmock/gtest/gtest.h:10204:5: note: in instantiation of member function 'testing::internal::RangeGenerator<api::Operation, int>::Iterator::Advance' requested here
Iterator(const ParamGeneratorInterface<T>* base, T value, int index,
^
third_party/gmock/gtest/gtest.h:10195:16: note: in instantiation of member function 'testing::internal::RangeGenerator<api::Operation, int>::Iterator::Iterator' requested here
return new Iterator(this, begin_, 0, step_);
^
third_party/gmock/gtest/gtest.h:10189:3: note: in instantiation of member function 'testing::internal::RangeGenerator<api::Operation, int>::Begin' requested here
RangeGenerator(T begin, T end, IncrementT step)
^
third_party/gmock/gtest/gtest.h:15815:11: note: in instantiation of member function 'testing::internal::RangeGenerator<api::Operation, int>::RangeGenerator' requested here
new internal::RangeGenerator<T, IncrementT>(start, end, step));
^
third_party/gmock/gtest/gtest.h:15820:10: note: in instantiation of function template specialization 'testing::Range<api::Operation, int>' requested here
return Range(start, end, 1);
^
enum_inc_real.cc:34:55: note: in instantiation of function template specialization 'testing::Range<api::Operation>' requested here
INSTANTIATE_TEST_CASE_P(Piping, FWTestPar, ::testing::Range(
^
If the templated operator+
is defined inside the api
namespace, then clang++ also accepts this code.
So, which compiler is right?
Do I really have to drag operator+
into every single namespace that contains an enum I want to increment?
The odd thing is that gtest does something similar to this:
namespace testin_ {
namespace intl {
template<typename T>
class PII {};
template<typename T, typename Inc>
class RG{
public:
RG(T begin, T end, Inc s)
: begin_{begin}, end_{end}, step_{s}, end_index_{CalculateEndIndex(begin, end, s)}
{}
T begin() { return begin_; }
T end () { return end_; }
private:
class It : public PII<T> {
void advance() {
value_ = value_ + step_;
}
T value_;
int index_;
Inc step_;
};
static int CalculateEndIndex(const T& begin,
const T& end,
const Inc& step) {
int end_index = 0;
for (T i = begin; i < end; i = i + step)
end_index++;
return end_index;
}
const T begin_;
const T end_;
const Inc step_;
const int end_index_;
};
} // intl
template<typename T, typename Inc>
intl::RG<T, Inc> Rg(T start, T end, Inc step) {
return intl::RG<T, Inc>(start, end, step);
}
}
auto gen = testin_::Rg(api::INSERT, api::DELETE, 1);
bu that is accepted without complaints by clang++
Aucun commentaire:
Enregistrer un commentaire