I am attempting to determine at compile time if all the values in a std::initializer_list are unique. I was able to locate a solution to valiate the size of a list but have been unable to apply it to the contents. I have tried with both free functions and in constructors but both approaches have resulted in the following errors with GCC 4.7.2.
error: non-constant condition for static assertion
error: 'begin' is not a constant expression
I realize the members of std::initializer_list are not declared constexpr but I'm hoping there is a solution like the size validation. Is it possible to validate the contents at compile time using something like the following?
#include <initializer_list>
template<typename InputIterator>
constexpr bool Validate(InputIterator begin, InputIterator end)
{
static_assert(*begin == *end, "begin and end are the same");
// The actual implemetnation is a single line recursive check.
return true;
}
template<typename InputType>
constexpr bool Validate(const std::initializer_list<InputType>& input)
{
// "-1" removed to simplify and eliminate potential cause of error
return Validate(input.begin(), input.end() /* - 1 */);
}
int main()
{
Validate({1, 2, 1});
}
After some digging it looks like using std::initializer_list is not possible in GCC 4.7 due to the lack of constexpr in it's declaration. It should work with GCC 4.8 as <initializer_list> has been updated to include constexpr. Unfortunately using GCC 4.8 is not an option at the moment.
It is possible to access elements of an array if the decayed pointer is passed by reference though. This allows the validation to occur as desired but still isn't quite the solution I am hoping for. The following code is a workable solution for arrays. It still requires that the size of the array be supplied to the validation function but that it easy enough to correct.
#include <initializer_list>
template<typename T>
constexpr bool Compare(T& data, int size, int needleIndex, int haystackIndex)
{
return
needleIndex == haystackIndex ?
Compare(data, size, needleIndex + 1, haystackIndex)
: needleIndex == size ?
false
: data[needleIndex] == data[haystackIndex] ?
true
: Compare(data, size, needleIndex + 1, haystackIndex);
}
template<typename T>
constexpr bool Compare(T& data, int size, int index)
{
return
index == size ?
false
: Compare(data, size, index + 1) ?
true
: Compare(data, size, 0, index);
}
template<typename T, int ArraySize>
constexpr bool Validate(T(&input)[ArraySize], int size)
{
return !Compare(input, size, 0);
}
int main()
{
constexpr int initData0[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
constexpr int initData1[] = {1, 1, 2, 3, 4, 5, 6, 7, 8, 9};
constexpr int initData2[] = {2, 1, 2, 3, 4, 5, 6, 7, 8, 9};
constexpr int initData3[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 8};
constexpr int initData4[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 7};
constexpr int initData5[] = {0, 1, 0, 3, 4, 5, 6, 7, 8, 9};
constexpr int initData6[] = {0, 1, 2, 3, 4, 5, 6, 9, 8, 9};
static_assert(Validate(initData0, 10), "set 0 failed"); // <-- PASS
static_assert(Validate(initData1, 10), "set 1 failed"); // <-- (and below) FAIL
static_assert(Validate(initData2, 10), "set 2 failed");
static_assert(Validate(initData3, 10), "set 3 failed");
static_assert(Validate(initData4, 10), "set 4 failed");
static_assert(Validate(initData5, 10), "set 5 failed");
static_assert(Validate(initData6, 10), "set 6 failed");
}
.
Build log:
C:\Source\SwitchCaseString\main.cpp: In function 'int main()':
C:\Source\SwitchCaseString\main.cpp:198:2: error: static assertion failed: set 1 failed
C:\Source\SwitchCaseString\main.cpp:199:2: error: static assertion failed: set 2 failed
C:\Source\SwitchCaseString\main.cpp:200:2: error: static assertion failed: set 3 failed
C:\Source\SwitchCaseString\main.cpp:201:2: error: static assertion failed: set 4 failed
C:\Source\SwitchCaseString\main.cpp:202:2: error: static assertion failed: set 5 failed
C:\Source\SwitchCaseString\main.cpp:203:2: error: static assertion failed: set 6 failed
Related
map insert comparison
Question> I try to understand the usage of insert & emplace with hint introduced to std::map. During the following test, it seems to me that the old fashion insert is fastest.
Did I do something wrong here?
Thank you
static void MapEmplaceWithHint(benchmark::State& state) {
std::vector<int> v{12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0};
std::map<int, int> mapInt;
auto where(std::end(mapInt));
for (auto _ : state) {
for (const auto &n : v) { // Items in non-incremental order
where = mapInt.emplace_hint(where, n, n+1);
}
}
}
BENCHMARK(MapEmplaceWithHint);
static void MapInsertWithHint(benchmark::State& state) {
std::vector<int> v{12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0};
std::map<int, int> mapInt;
auto where(std::end(mapInt));
for (auto _ : state) {
for (const auto &n : v) { // Items in non-incremental order
where = mapInt.insert(where, {n, n+1});
}
}
}
BENCHMARK(MapInsertWithHint);
static void MapInsertNoHint(benchmark::State& state) {
std::vector<int> v{12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0};
std::map<int, int> mapInt;
for (auto _ : state) {
for (const auto &n : v) { // Items in non-incremental order
mapInt.insert({n, n+1});
}
}
}
BENCHMARK(MapInsertNoHint);
static void MapReverseInsertNoHint(benchmark::State& state) {
std::vector<int> v{0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 11, 12};
std::map<int, int> mapInt;
for (auto _ : state) {
for (const auto &n : v) { // Items in incremental order
mapInt.insert({n, n+1});
}
}
}
BENCHMARK(MapReverseInsertNoHint);
static void MapEmplaceNoHint(benchmark::State& state) {
std::vector<int> v{12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0};
std::map<int, int> mapInt;
for (auto _ : state) {
for (const auto &n : v) { // Items in non-incremental order
mapInt.emplace(n, n+1);
}
}
}
BENCHMARK(MapEmplaceNoHint);
First, let's create a dataset more meaningful than 12 integers:
std::vector<int> v(10000);
std::iota(v.rbegin(), v.rend(), 0);
Results from all functions are now more comparable: https://quick-bench.com/q/HW3eYL1RaFMCJvDdGLBJwEbDLdg
However, there's a worse thing. Notice that looping over state makes it perform the same operations several times to measure the average time. But, since you are reusing the same map, each insert or emplace after the first loop iteration is failing, so you mostly measure time of failed inserts, where hint doesn't help.
Test cases should look more like this:
std::vector<int> v(1000);
std::iota(v.rbegin(), v.rend(), 0);
for (auto _ : state) {
std::map<int, int> mapInt;
auto where(std::end(mapInt));
for (const auto &n : v) { // Items in non-incremental order
where = mapInt.emplace_hint(where, n, n+1);
}
}
And with this, hints start to shine (had to limit data to 1000, otherwise I'd get timeouts): https://quick-bench.com/q/2cR4zU_FZ5HQ6owPj9Ka_y9FtZE
I'm not sure if the benchmarks are correct, but quick glance in the assembly suggests that inserts were not optimized altogether, so there's a chance it's good enough.
As noticed by Ted Lyngmo, try_emplace() with hint tends to perform (slightly) better:
https://quick-bench.com/q/evwcw4ovP20qJzfsyl6M-_37HzI
I want to write a function like this:
template<class IterableType>
void CheckAndProcessIterables(IterableType& a, IterableType& b, IterableType& c) {
IteratorRangeType range{}; // empty range
if (Check(a)) {
range = boost::range::join(range, a);
}
if (Check(b)) {
range = boost::range::join(range, b);
}
if (Check(c)) {
range = boost::range::join(range, c);
}
Process(range);
}
Is it possible? Which type should I use instead of IteratorRangeType?
As far as I understand it, boost::range::join return type depends on it's arguments. Is there some wrapper class which can be assigned any type of range as long as its underlying value type is same?
You can use type erased iterator ranges, which Boost has in the form of any_range.
Beware of the performance cost of these, which can quickly become very noticable. I'd rethink the approach unless you're very sure that this not on any hot path and readability is a much more of a concern than performance.
Live On CoCompiler Explorer
#include <boost/range/join.hpp>
#include <boost/range/any_range.hpp>
// for demo only:
#include <boost/range/algorithm/for_each.hpp>
#include <boost/lambda/lambda.hpp>
#include <fmt/ranges.h>
template<class Range>
bool Check(Range const& r) {
bool odd_len = boost::size(r) % 2;
fmt::print("Check {}, odd_len? {}\n", r, odd_len);
return odd_len;
}
template<class Range>
void Process(Range const& r) {
fmt::print("Processing {}\n", r);
using namespace boost::lambda;
for_each(r, _1 *= _1);
}
template<class IterableType>
void CheckAndProcessIterables(IterableType& a, IterableType& b, IterableType& c) {
using V = typename boost::range_value<IterableType>::type;
using ErasedRange= boost::any_range<V, boost::forward_traversal_tag>;
ErasedRange range{}; // empty range
if (Check(a)) {
range = boost::range::join(range, a);
}
if (Check(b)) {
range = boost::range::join(range, b);
}
if (Check(c)) {
range = boost::range::join(range, c);
}
Process(range);
}
int main() {
std::vector a{1, 2, 3}, b{4, 5}, c{6, 7, 8};
CheckAndProcessIterables(a, b, c);
fmt::print("After process: a:{} b:{} c:{}\n", a, b, c);
}
Prints
Check {1, 2, 3}, odd_len? true
Check {4, 5}, odd_len? false
Check {6, 7, 8}, odd_len? true
Processing {1, 2, 3, 6, 7, 8}
After process: a:{1, 4, 9} b:{4, 5} c:{36, 49, 64}
I'm running a test with microsoft native unit testing framework (that comes with vs2019) and it fails with this message: Assert failed. Expected:<1> Actual:<1>
Here is the test code:
TEST_METHOD(memory_copy)
{
int ref[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
int src[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
int dest[10];
test::memory_copy<int>(src, dest, 10);
for (unsigned int i = 0; i < 10; i++)
{
Assert::AreSame(src[i], ref[i]);
Assert::AreSame(dest[i], ref[i]);
}
};
Note: memory_copy<>() copies memory from one pointer to another, just like std::memcpy()
Does anyone have an idea what may be the issue here?
Assert::AreSame() checks whether the inputs refer to the same object; it does not compare the values.
The implementation of the function (from CppUnitTestAssert.h) is as follows:
template<typename T> static void AreSame(const T& expected, const T& actual, const wchar_t* message = NULL, const __LineInfo* pLineInfo = NULL)
{
FailOnCondition(&expected == &actual, EQUALS_MESSAGE(expected, actual, message), pLineInfo);
}
What you can see here, is that it's comparing memory addresses, as opposed to the contents. Assert::AreEqual, on the other hand, compares the objects for equality.
template<typename T> static void AreEqual(const T& expected, const T& actual, const wchar_t* message = NULL, const __LineInfo* pLineInfo = NULL)
{
FailOnCondition(expected == actual, EQUALS_MESSAGE(expected, actual, message), pLineInfo);
}
It turns out that Assert::AreSame() doesn't do what I expected it to do. By changing it to Assert::AreEqual() I've solved the issue. More info here:
Microsoft Documentation on AreEqual()
I am trying to initialize an std::unordered_map using the constructor that accepts data through an initialization list and the initial number of buckets.
For some reason, that constructor works if I put it in main, but has a syntax error when I put it in a class header.
Specifically, the header, called momo.h:
#pragma once
#include <unordered_map>
namespace std
{
template <>
struct hash<std::pair<uint16_t, uint16_t>>
{
std::size_t operator()(const std::pair<uint16_t, uint16_t>& k) const
{
return (std::hash<long>()((((long)k.first) << 16) + (long)k.second));
}
};
}
class test
{
std::unordered_map<std::pair<uint16_t, uint16_t>, uint16_t> m_Z(
{ /* Fails here: syntax error: missing ')' before '{' */
{std::pair{ 1, 2 }, 3},
{std::pair{ 4, 5 }, 6}
}, 128);
};
While if I remove the definition from the header into main thus:
#include "Momo.h"
int main()
{
test X;
std::unordered_map<std::pair<uint16_t, uint16_t>, uint16_t> Y(
{
{std::pair{ 1, 2 }, 3},
{std::pair{ 4, 5 }, 6}
}, 128);
}
The code compiles without error. Why?
You need to braced-init-list(or uniform-initiation) the std::unordered_map in the class.
class test
{
std::unordered_map<std::pair<uint16_t, uint16_t>, uint16_t> m_Z{ // >> brased init
{
{std::pair{ 1, 2 }, 3},
{std::pair{ 4, 5 }, 6}
}, 128
}; // >>>
};
I have a following code:
LicMessage message;
int oid[] = { 1, 3, 6, 1, 4, 1, 9363, 1, 5, 0 };
int ret1 = OBJECT_IDENTIFIER_set_arcs(&message.getMsg()->lic_ModuleID, oid, sizeof(oid[0]), sizeof(oid) / sizeof(oid[0]));
LicMessage class:
LicMessage::LicMessage() : licMsg(new LIC_Msg_t)
{
}
LIC_Msg_t* const LicMessage::getMsg () const
{
return licMsg.get();
}
std::auto_ptr<LIC_Msg_t> licMsg;
LIC_Msg_t is generated by asn1c has OBJECT_IDENTIFIER_t lic_ModuleID; as a field.
It fails for some reason * glibc detected build/tests//tests: free(): invalid pointer: 0x0000003ccab8e018 **
Could you please advice me what I'm doing wrong?
You are losing pointer when you request the memory. You should allocated memory by malloc
.