Search in a vector of structs - c++

I have a vector full with structs look like this
struct person_t
{
string name;
string id;
struct location_t location;
};
vector <person_t> myvector;
and i have read in the items in myvector
but now i need to know how to search for specific item in vector and count how many of that item it is in the vector.

unsigned int count = std::count_if( myvector.begin(), myvector.begin(),
[]( const person_t & p ) { return p.name == "Bill Gates"; }
);
or without c++11
struct EqualByName {
EqualByName( const std::string & name ) : m_name( name ) {}
bool operator()( const person_t & p ) const { return p.name == m_name; }
private:
std::string m_name;
};
unsigned int count = std::count_if( myvector.begin(), myvector.begin(),
EqualByName( "Bill Gates" )
);
or ugly looking but for all occasions ))
template< class T, class FieldType, FieldType T::*FieldPtr >
struct EqualBy
{
EqualBy( const FieldType & value ) : m_fieldValue( value ) {}
bool operator()( const T & r ) const {
return m_fieldValue == r.*FieldPtr;
}
bool operator()( const T * p ) const {
return m_fieldValue == p->*FieldPtr;
}
private:
const FieldType m_fieldValue;
};
// usage:
typedef EqualBy< person_t, std::string, & person_t::name > EqualByName;
typedef EqualBy< person_t, std::string, & person_t::id > EqualById;
unsigned int namesCount = std::count_if( myvector.begin(), myvector.end(),
EqualByName( "Bill Gates" )
);
unsigned int idsCount = std::count_if( myvector.begin(), myvector.end(),
EqualById( "123456" )
);

Related

How can I reduce the function template specializations?

I'm trying to write a property validator to be used in UE4, using their reflection system.
I first came up with this:
class FDataValidator
{
public:
FDataValidator( UObject & object, TArray< FText > & validation_errors ) :
Object( object ),
ValidationResult( validation_errors.Num() == 0 ? EDataValidationResult::Valid : EDataValidationResult::Invalid ),
ObjectClass( Object.GetClass() ),
ValidationErrors( validation_errors )
{}
template < class _TYPE_ >
FDataValidator & GreaterThan( const FName property_name, const _TYPE_ value );
EDataValidationResult Result() const
{
return ValidationResult;
}
private:
template < class _PROPERTY_TYPE_, class _VALUE_TYPE_, class _COMPARATOR_TYPE_ >
FDataValidator & CompareProperty( const FName property_name, const _VALUE_TYPE_ value, _COMPARATOR_TYPE_ comparator = _COMPARATOR_TYPE_() )
{
if ( auto * property = GetTypedProperty< _PROPERTY_TYPE_ >( property_name ) )
{
const auto property_value = property->GetPropertyValue_InContainer( &Object );
if ( !comparator( property_value, value ) )
{
AddError( FText::FromString( FString::Printf( TEXT( "%s must be greater than %f" ), *property_name.ToString(), value ) ) );
}
}
return *this;
}
template < class _PROPERTY_TYPE_ >
_PROPERTY_TYPE_ * GetTypedProperty( const FName property_name )
{
if ( auto * property = ObjectClass->FindPropertyByName( property_name ) )
{
if ( auto * typed_property = Cast< _PROPERTY_TYPE_ >( property ) )
{
return typed_property;
}
}
return nullptr;
}
void AddError( FText text )
{
ValidationErrors.Emplace( text );
ValidationResult = EDataValidationResult::Invalid;
}
UObject & Object;
EDataValidationResult ValidationResult;
UClass * ObjectClass;
TArray< FText > & ValidationErrors;
};
template <>
FDataValidator & FDataValidator::GreaterThan< float >( const FName property_name, const float value )
{
return CompareProperty< UFloatProperty, float, std::greater< float > >( property_name, value );
}
template <>
FDataValidator & FDataValidator::GreaterThan< int >( const FName property_name, const int value )
{
return CompareProperty< UIntProperty, int, std::greater< int > >( property_name, value );
}
I only implemented GreaterThan for 2 types, and I'd like to know if I can not refactor the class to avoid so many template specializations.
Would it be possible to have something like that, where I pass for example std::greater< _VALUE_TYPE_ > around and let the system infer what _VALUE_TYPE_ is to call GetTypedProperty with the correct type?
class FDataValidator
{
public:
template < class _VALUE_TYPE_ >
FDataValidator & GreaterThan( const FName property_name, const _VALUE_TYPE_ value )
{
return NumericComparator< std::greater< _VALUE_TYPE_ > >( property_name, value );
}
private:
// How to write this to infer for example that _VALUE_TYPE_ is float when passed std::greater< float > ?
template < typename _COMPARATOR_TYPE_ >
FDataValidator & NumericComparator( FName property_name, _VALUE_TYPE_ value, _COMPARATOR_TYPE_ comparator = _COMPARATOR_TYPE_() );
};
template < class _VALUE_TYPE_, class _COMPARATOR_TYPE_ >
FDataValidator & NumericComparator( FName property_name, _VALUE_TYPE_ value, _COMPARATOR_TYPE_ comparator = _COMPARATOR_TYPE_() )
{
return CompareProperty< UFloatProperty, float, std::greater< float > >( property_name, value );
}
Thanks
UFloatProperty and other numeric types seem to inherit from TProperty_Numeric<T>.
So something like this might be a solution:
template <typename T>
FDataValidator& FDataValidator::GreaterThan<T>(const FName property_name, const T value)
{
return CompareProperty<TProperty_Numeric<T>, T, std::greater<T>>(property_name, value);
}

Enum convert to string using compile time constants

I'm trying to associate compile time strings to enum values.
Here is my first attempt at the problem:
EnumValue will do the compile time assocation between a string and an enum
template<typename EnumType, int EnumIntValue, const char* EnumStrValue>
class EnumValue
{
public:
static const char* toString()
{
return EnumStrValue;
}
static const int toInt()
{
return EnumIntValue;
}
static EnumType get()
{
return static_cast<EnumType>(EnumIntValue);
}
};
EnumValueHolder will hold the actual values for both string and enum.
I dislike my current design as it still needs to hold a pointer to string. I would prefer a compile time association for this but fail to come up with a more elegant solution
template<typename EnumType>
class EnumValueHolder
{
public:
EnumValueHolder()
{}
EnumValueHolder(const EnumType& value, const char* str)
: value(value), str(str)
{}
bool operator==(const EnumValueHolder<EnumType>& rhs) { return value == rhs.value; }
bool operator==(const EnumType& rhs)const { return value == rhs; }
operator EnumType()const
{
return value;
}
const char* toString()const
{
return str;
}
const int toInt()const
{
return static_cast<int>(value);
}
private:
EnumType value;
char const* str;
};
Marcos to easily refer to enum types and enum value holder construction
#define ENUM_VALUE_TYPE(enumName, enumValue) \
EnumValue<enumName, (int)enumName::enumValue, str_##enumValue>
#define ENUM_VALUE_MAKE(enumName, enumValue) \
EnumValueHolder<enumName> { \
ENUM_VALUE_TYPE(enumName, enumValue)::get(), \
ENUM_VALUE_TYPE(enumName, enumValue)::toString() }
The following are my test cases and usage examples:
const char str_Apple[] = "Apple";
const char str_Orange[] = "Orange";
const char str_Pineapple[] = "Pineapple";
enum class EFruits
{
Apple,
Orange,
Pineapple
};
int main()
{
auto evApple = ENUM_VALUE_MAKE(EFruits, Apple);
std::cout << evApple.toString() << std::endl;
auto evOrange = ENUM_VALUE_MAKE(EFruits, Orange);
std::cout << evOrange.toString() << std::endl;
std::cout << "compare: " << (evApple == evOrange) << std::endl;
evApple = evOrange;
std::cout << evApple.toString() << std::endl;
auto myfruit = ENUM_VALUE_MAKE(EFruits, Pineapple);
std::cout << myfruit.toString() << std::endl;
switch (myfruit)
{
case EFruits::Apple:
std::cout << "Im an apple!" << std::endl;
break;
case EFruits::Orange:
std::cout << "Im an Orange!" << std::endl;
break;
case EFruits::Pineapple:
std::cout << "Im a Pineapple!" << std::endl;
break;
default:break;
}
}
One of the objectives is to remove the global string:
const char str_Apple[] = "Apple";
const char str_Orange[] = "Orange";
const char str_Pineapple[] = "Pineapple";
The other is to create a macro that assoicates an enum with a string
//Some crazy define that makes pairs of enum values and strings as
//compile time constants
#define DEFINE_ENUM_STRING(enumValue)\
enumValue, #enumValue
//Ideally, the macro would be used like this. This should be usable in any
//scope (global, namespace, class)
//with any access specifier (private, protected, public)
enum class EFruits
{
DEFINE_ENUM_STRING(Apple),
DEFINE_ENUM_STRING(Orange),
DEFINE_ENUM_STRING(Pineapple)
};
So there are 2 main questions:
1) Will this current design actually guarantee compile time constants for associating the enum to the string?
2) How can I define a macro to stringify an enum value and declare the value in a enum class using 1 line?
Edit: This should work and compile with msvs2017 on win64 platform using c++ 11.
Thanks.
I think it should work with MSVC2017. It uses C++14 in the constexpr functions but you can split them to single return statement constexprs to be C++11 compatible (however MSVC2017 supports C++14).
EnumConverter stores the char*, the enum and a string hash value for each enum entry. For each enum you must specialize EnumConverter::StrEnumContainer. The enum-string pairs could be generated with a similar macro you specified.
#include <tuple>
#include <array>
#include <stdexcept>
using namespace std;
enum ELogLevel {
Info,
Warn,
Debug,
Error,
Critical
};
static constexpr size_t constexprStringHash( char const* const str ) noexcept
{
return (
( *str != 0 ) ?
( static_cast< size_t >( *str ) + 33 * constexprStringHash( str + 1 ) ) :
5381
);
}
class EnumConverter final
{
public:
EnumConverter() = delete;
EnumConverter( const EnumConverter& ) = delete;
EnumConverter( EnumConverter&& ) = delete;
EnumConverter& operator =( const EnumConverter& ) = delete;
EnumConverter& operator =( EnumConverter&& ) = delete;
template< typename ENUM_T >
static constexpr const char* toStr( const ENUM_T value )
{
const auto& strEnumArray{ StrEnumContainer< ENUM_T >::StrEnumPairs };
const char* result{ nullptr };
for( size_t index{ 0 }; index < strEnumArray.size(); ++index ) {
if( std::get< 1 >( strEnumArray[ index ] ) == value ) {
result = std::get< 0 >( strEnumArray[ index ] );
break;
}
}
return ( ( result == nullptr ) ? throw std::logic_error{ "Enum toStrBase conversion failed" } : result );
}
template< typename ENUM_T >
static constexpr ENUM_T fromStr( const char* const str )
{
const auto& strEnumArray{ StrEnumContainer< ENUM_T >::StrEnumPairs };
const size_t hash{ constexprStringHash( str ) };
const ENUM_T* result{ nullptr };
for( size_t index{ 0 }; index < strEnumArray.size(); ++index ) {
if( std::get< 2 >( strEnumArray[ index ] ) == hash ) {
result = &( std::get< 1 >( strEnumArray[ index ] ) );
}
}
return ( ( result == nullptr ) ? throw std::logic_error{ "Enum toStrBase conversion failed" } : *result );
}
private:
template< typename ENUM_T, size_t LEN >
using ARRAY_T = std::array< std::tuple< const char* const, const ENUM_T, const size_t >, LEN >;
template< typename ENUM_T >
static constexpr std::tuple< const char* const, ENUM_T, size_t > getTuple( const char* const str, const ENUM_T type ) noexcept
{
return std::tuple< const char* const, ENUM_T, size_t >{ str, type, constexprStringHash( str ) };
}
template< typename ENUM_T >
struct StrEnumContainer
{
};
template< typename ENUM_T >
friend struct StrEnumContainer;
};
template<>
struct EnumConverter::StrEnumContainer< ELogLevel >
{
using ENUM_T = ELogLevel;
static constexpr EnumConverter::ARRAY_T< ENUM_T, 5 > StrEnumPairs{ {
{ getTuple( "Info", ENUM_T::Info ) },
{ getTuple( "Warn", ENUM_T::Warn ) },
{ getTuple( "Debug", ENUM_T::Debug ) },
{ getTuple( "Error", ENUM_T::Error ) },
{ getTuple( "Critical", ENUM_T::Critical ) },
} };
};
int main()
{
//static_assert( EnumConverter::fromStr< ELogLevel >( "Info" ) == EnumConverter::fromStr< ELogLevel >( EnumConverter::toStr( Error ) ), "Error" ); // Error
static_assert(
EnumConverter::toStr( Warn )[ 0 ] == 'W' &&
EnumConverter::toStr( Warn )[ 1 ] == 'a' &&
EnumConverter::toStr( Warn )[ 2 ] == 'r' &&
EnumConverter::toStr( Warn )[ 3 ] == 'n',
"Error"
);
static_assert( EnumConverter::fromStr< ELogLevel >( "Info" ) == EnumConverter::fromStr< ELogLevel >( EnumConverter::toStr( Info ) ), "Error" );
}

std::variant, a wrapper class, and 'conversion from ... to non-scalar type ... requested'

I have mutually recursive variant types: Value, Array, and Object. The crux of the matter is that I can assign one of the variant types to a Value when it is nested within an Array or Object, which can both contain Value. I cannot assign directly to a Value. The main() function code at the bottom should make this clear. The compiler (GNU GCC 7.2) gives me errors like:
error: conversion from 'JSON::Integer {aka long unsigned int}' to non-scalar type 'JSON::Value' requested
Value v = Integer( 7 );
and oddly does not provide any additional information about assignment operator candidates or anything else. Further, it isn't clear to me how assignment operators I have defined in Value are affecting this problem. Complete working example code follows. Any assignment of one of the variant types directly to a Value type in main() causes a compiler error just like the one above for the Integer type.
Thanks in advance!
Object Class
#ifndef JSON_OBJECT_HPP
#define JSON_OBJECT_HPP
#include <iomanip>
#include <string>
#include <unordered_map>
#include "Value.hpp"
namespace JSON {
class Object {
public:
using Key = std::string;
private:
using values_t = std::unordered_map<Key,Value>;
values_t values;
public:
Object() = default;
Value & operator[]( Key const & key ) {
auto it = values.emplace( key, Value() );
return it.first->second;
}
Value const & operator[]( Key const & key ) const {
auto it = values.find( key );
return it->second;
}
bool has_key( Key const & key ) const {
auto it = values.find( key );
return it != values.end();
}
bool operator==( Object const & rhs ) const {
return values == rhs.values;
}
values_t::const_iterator begin() const {
return values.begin();
}
values_t::const_iterator end( ) const {
return values.end();
}
values_t::iterator begin() {
return values.begin();
}
values_t::iterator end() {
return values.end();
}
};
bool operator==( Object const & lhs, Object const & rhs ) {
return lhs.operator==( rhs );
}
std::ostream & operator<<( std::ostream & os, Object const & object ) {
os << '{';
auto begin = object.begin();
auto end = object.end();
if( begin != end ) {
os << std::quoted( begin->first ) << ':' << begin->second;
}
while( ++begin != end ) {
os << ',' << std::quoted( begin->first ) << ':' << begin->second;
}
os << '}';
}
}
#endif
Array Class
#ifndef JSON_ARRAY_HPP
#define JSON_ARRAY_HPP
#include <vector>
#include "types.hpp"
#include "Value.hpp"
namespace JSON {
std::ostream & operator<<( std::ostream &, Value & );
class Array {
private:
using values_t = std::vector<Value>;
values_t values;
public:
using Key = values_t::size_type;
Array() = default;
Value & operator[]( Key key ) {
if( !has_key( key ) ) {
values.resize( key + 1 );
}
return values[key];
}
Value const & operator[]( Key key ) const {
return values[key];
}
bool has_key( Key key ) const {
return key < values.size();
}
bool operator==( Array const & rhs ) const {
return values == rhs.values;
}
values_t::const_iterator begin() const {
return values.begin();
}
values_t::const_iterator end( ) const {
return values.end();
}
values_t::iterator begin() {
return values.begin();
}
values_t::iterator end() {
return values.end();
}
};
bool operator==( Array const & lhs, Array const & rhs ) {
return lhs.operator==( rhs );
}
std::ostream & operator<<( std::ostream & os, Array const & array ) {
os << '[';
auto begin = array.begin();
auto end = array.end();
if( begin != end ) {
os << *begin;
}
while( ++begin != end ) {
os << ',' << *begin;
}
os << ']';
}
}
#endif
Value Class
#ifndef JSON_VALUE_HPP
#define JSON_VALUE_HPP
#include <iomanip>
#include <type_traits>
#include <variant>
#include <boost/variant/variant.hpp>
#include <boost/variant/recursive_wrapper.hpp>
#include "types.hpp"
namespace JSON {
class Object;
class Array;
bool operator==( Object const & lhs, Object const & rhs );
bool operator==( Array const & lhs, Array const & rhs );
std::ostream & operator<<( std::ostream &, Object const & object );
std::ostream & operator<<( std::ostream &, Array const & array );
template<class T> struct always_false : std::false_type {};
class Value {
private:
using variant_t = std::variant<Undefined,String,Integer,Number,boost::recursive_wrapper<Object>,boost::recursive_wrapper<Array> >;
variant_t data;
friend std::ostream & operator<<( std::ostream & os, Value const & value );
public:
Value() = default;
bool operator==( Value const & rhs ) const {
return std::visit(
[]( auto && lhs, auto && rhs ) -> bool {
using lhsT = std::decay_t<decltype( lhs )>;
using rhsT = std::decay_t<decltype( rhs )>;
if constexpr ( std::is_same_v< lhsT, rhsT> ) {
if constexpr (std::is_same_v< lhsT, boost::recursive_wrapper<Object> > ) {
return lhs.get() == rhs.get();
} else if constexpr (std::is_same_v< lhsT, boost::recursive_wrapper<Array> > ) {
return lhs.get() == rhs.get();
} else {
return lhs == rhs;
}
} else {
return false;
}
},
data,
rhs.data
);
}
Value & operator=( String const & rhs ) {
data = rhs;
return *this;
}
Value & operator=( Integer const & rhs ) {
data = rhs;
return *this;
}
Value & operator=( Object const & rhs ) {
data = rhs;
return *this;
}
Value & operator=( Array const & rhs ) {
data = rhs;
return *this;
}
};
std::ostream & operator<<( std::ostream & os, Value const & value ) {
std::visit(
[&os]( auto && arg ) {
using T = std::decay_t<decltype( arg )>;
if constexpr ( std::is_same_v< T, Undefined > ) {
os << "undefined";
} else if constexpr ( std::is_same_v< T, String > ) {
os << std::quoted( arg );
} else if constexpr ( std::is_same_v< T, Integer > ) {
os << arg;
} else if constexpr ( std::is_same_v< T, Number > ) {
os << arg;
} else if constexpr ( std::is_same_v< T, boost::recursive_wrapper<Object> > ) {
os << arg.get();
} else if constexpr ( std::is_same_v< T, boost::recursive_wrapper<Array> > ) {
os << arg.get();
} else if constexpr ( std::is_same_v< T, Boolean > ) {
os << (arg == false ? "false" : "true");
} else if constexpr ( std::is_same_v< T, Null > ) {
os << "null";
} else {
static_assert( always_false<T>::value, "non-exhaustive visitor" );
}
},
value.data
);
}
}
#endif
Type Definitions
#ifndef TYPES_HPP
#define TYPES_HPP
namespace JSON {
template <typename Tag> struct Literal {
bool operator==( Literal const & ) const {
return true;
}
bool operator<( Literal const & ) const {
return false;
}
};
using String = std::string;
using Integer = uint64_t;
using Number = double;
class Object;
class Array;
using Boolean = bool;
using Null = Literal<struct tag_null>;
using Undefined = Literal<struct tag_undefined>;
}
#endif
Main Code
#include <iostream>
#include "Array.hpp"
#include "Object.hpp"
#include "Value.hpp"
using namespace JSON;
int main() {
Object o;
o["fun"] = "what?"; // compiles fin
o["stuff"] = "yeah!"; // compiles fine
o["inttest"] = Integer( 44 ); // compiles fine
Array a;
a[2] = "yo"; // compiles fine
a[3] = Integer( 6 ); // compiles fine
o["arrtest"] = a;
// Value v = a; // fails to compile
Value v = Integer( 7 ); // fails to compile
std::cout << v;
std::cout << o << "\n";
std::cout << a << "\n";
return 0;
}
This was a bad question with an embarrassing oversight. As the commenter pointed out, the problematic lines in main() were initializations rather than assignments. Providing the appropriate constructors solved the problem. For completeness, corrected code follows. It compiles and works fine under GNU GCC 7.2.
Object Class
#ifndef JSON_OBJECT_HPP
#define JSON_OBJECT_HPP
#include <iomanip>
#include <string>
#include <unordered_map>
#include "Value.hpp"
namespace JSON {
class Object {
public:
using Key = std::string;
private:
using values_t = std::unordered_map<Key,Value>;
values_t values;
public:
Object() = default;
Value & operator[]( Key const & key ) {
auto it = values.emplace( key, Value() );
return it.first->second;
}
Value const & operator[]( Key const & key ) const {
auto it = values.find( key );
return it->second;
}
bool has_key( Key const & key ) const {
auto it = values.find( key );
return it != values.end();
}
bool operator==( Object const & rhs ) const {
return values == rhs.values;
}
values_t::const_iterator begin() const {
return values.begin();
}
values_t::const_iterator end( ) const {
return values.end();
}
values_t::iterator begin() {
return values.begin();
}
values_t::iterator end() {
return values.end();
}
};
bool operator==( Object const & lhs, Object const & rhs ) {
return lhs.operator==( rhs );
}
std::ostream & operator<<( std::ostream & os, Object const & object ) {
os << '{';
auto begin = object.begin();
auto end = object.end();
if( begin != end ) {
os << std::quoted( begin->first ) << ':' << begin->second;
}
while( ++begin != end ) {
os << ',' << std::quoted( begin->first ) << ':' << begin->second;
}
os << '}';
}
}
#endif
Array Class
#ifndef JSON_ARRAY_HPP
#define JSON_ARRAY_HPP
#include <vector>
#include "types.hpp"
#include "Value.hpp"
namespace JSON {
std::ostream & operator<<( std::ostream &, Value const & );
class Array {
private:
using values_t = std::vector<Value>;
values_t values;
public:
using Key = values_t::size_type;
Array() = default;
Value & operator[]( Key key ) {
if( !has_key( key ) ) {
values.resize( key + 1 );
}
return values[key];
}
Value const & operator[]( Key key ) const {
return values[key];
}
bool has_key( Key key ) const {
return key < values.size();
}
bool operator==( Array const & rhs ) const {
return values == rhs.values;
}
values_t::const_iterator begin() const {
return values.begin();
}
values_t::const_iterator end( ) const {
return values.end();
}
values_t::iterator begin() {
return values.begin();
}
values_t::iterator end() {
return values.end();
}
};
bool operator==( Array const & lhs, Array const & rhs ) {
return lhs.operator==( rhs );
}
std::ostream & operator<<( std::ostream & os, Array const & array ) {
os << '[';
auto begin = array.begin();
auto end = array.end();
if( begin != end ) {
os << *begin;
}
while( ++begin != end ) {
os << ',' << *begin;
}
os << ']';
}
}
#endif
Value Class
#ifndef JSON_VALUE_HPP
#define JSON_VALUE_HPP
#include <iomanip>
#include <type_traits>
#include <variant>
#include <boost/variant/variant.hpp>
#include <boost/variant/recursive_wrapper.hpp>
#include "types.hpp"
namespace JSON {
class Object;
class Array;
bool operator==( Object const & lhs, Object const & rhs );
bool operator==( Array const & lhs, Array const & rhs );
std::ostream & operator<<( std::ostream &, Object const & object );
std::ostream & operator<<( std::ostream &, Array const & array );
template<class T> struct always_false : std::false_type {};
class Value {
private:
using variant_t = std::variant<Undefined,String,Integer,Number,boost::recursive_wrapper<Object>,boost::recursive_wrapper<Array> >;
variant_t data;
friend std::ostream & operator<<( std::ostream & os, Value const & value );
public:
Value() = default;
template <typename T> Value( T const & rhs ) : data( rhs ) {}
bool operator==( Value const & rhs ) const {
return std::visit(
[]( auto && lhs, auto && rhs ) -> bool {
using lhsT = std::decay_t<decltype( lhs )>;
using rhsT = std::decay_t<decltype( rhs )>;
if constexpr ( std::is_same_v< lhsT, rhsT> ) {
if constexpr (std::is_same_v< lhsT, boost::recursive_wrapper<Object> > ) {
return lhs.get() == rhs.get();
} else if constexpr (std::is_same_v< lhsT, boost::recursive_wrapper<Array> > ) {
return lhs.get() == rhs.get();
} else {
return lhs == rhs;
}
} else {
return false;
}
},
data,
rhs.data
);
}
};
std::ostream & operator<<( std::ostream & os, Value const & value ) {
std::visit(
[&os]( auto && arg ) {
using T = std::decay_t<decltype( arg )>;
if constexpr ( std::is_same_v< T, Undefined > ) {
os << "undefined";
} else if constexpr ( std::is_same_v< T, String > ) {
os << std::quoted( arg );
} else if constexpr ( std::is_same_v< T, Integer > ) {
os << arg;
} else if constexpr ( std::is_same_v< T, Number > ) {
os << arg;
} else if constexpr ( std::is_same_v< T, boost::recursive_wrapper<Object> > ) {
os << arg.get();
} else if constexpr ( std::is_same_v< T, boost::recursive_wrapper<Array> > ) {
os << arg.get();
} else if constexpr ( std::is_same_v< T, Boolean > ) {
os << (arg == false ? "false" : "true");
} else if constexpr ( std::is_same_v< T, Null > ) {
os << "null";
} else {
static_assert( always_false<T>::value, "non-exhaustive visitor" );
}
},
value.data
);
}
}
#endif
Type Definitions
#ifndef JSON_TYPES_HPP
#define JSON_TYPES_HPP
namespace JSON {
template <typename Tag> struct Literal {
bool operator==( Literal const & ) const {
return true;
}
bool operator<( Literal const & ) const {
return false;
}
};
using String = std::string;
using Integer = uint64_t;
using Number = double;
class Object;
class Array;
using Boolean = bool;
using Null = Literal<struct tag_null>;
using Undefined = Literal<struct tag_undefined>;
}
#endif
Main Code
#include <iostream>
#include "Array.hpp"
#include "Object.hpp"
#include "Value.hpp"
using namespace JSON;
int main() {
Object o;
o["fun"] = "what?";
o["stuff"] = "yeah!";
o["inttest"] = Integer( 44 );
Array a;
a[2] = "yo";
a[3] = Integer( 6 );
o["arrtest"] = a;
// Value v = a;
Value v = Integer( 7 );
std::cout << v << "\n";
std::cout << o << "\n";
std::cout << a << "\n";
return 0;
}

Cython : exposing C++ classes with nested typedef (s)

According to this question/answer in stackoverflow, it is not possible to directly rewrite C++ nested typedefs in cython. I have such a problem and I don't know which is the right/optimal way to proceed.
Let me be more specific with an example. Below, you can find the content of two C++ files (one header.h and one .cpp) and of two corresponding cython files (one .pxd and one .pyx). In the C++ header file called cpp_graph.h you can see nested typedef declarations; for example, that corresponding to Graph::iterator::nn_iterator. I don't know how to expose that in the corresponding graph.pxd file. Or, in other words, I don't know what is the "official" or "standard" way to do it.
Some relevant information. If you check the cython wrapper for STL you can find nested typedefs. For example here in the utility.pxd or here in the vector.pxd file. However, those nested usages of ctypedef are used for template declarations only. Is it the case that nested typedefs work for template declarations only in cython?
The C++ header file:
// file : cpp_graph.h
#ifndef Included_cpp_graph
#define Included_cpp_graph
#include <cassert>
#include <cstddef>
#include <set>
#include <map>
#include <iostream>
#include <string>
#include <sstream>
#include "to_string_patch.h"
#ifndef Defined_bint
#define Defined_bint
typedef int bint;
#endif
class Graph {
public:
typedef std::set< int > t_nn;
typedef std::set< int >::iterator nn_iterator;
typedef std::map< int , t_nn > t_node_to_nn;
class iterator
{
// To iterate over nodes.
friend class Graph;
public:
typedef iterator self_type;
typedef int value_type;
typedef int & reference;
typedef int * pointer;
typedef t_node_to_nn::iterator map_iterator;
typedef std::forward_iterator_tag iterator_category;
iterator( map_iterator map_it ) : _map_it( map_it ) { }
self_type operator++() { _map_it++; return *this; } // PREFIX
self_type operator++(int junk) { self_type i = *this; _map_it++; return i; } // POSTFIX
value_type operator*() { return ( * _map_it ).first; } // Return the index "i"
Graph::t_nn * operator->() { return & ( * _map_it ).second; } // Return a pointer to the contained t_nn.
bool operator==( const self_type & rhs ) { return _map_it == rhs._map_it; }
bool operator!=( const self_type & rhs ) { return _map_it != rhs._map_it; }
private:
map_iterator _map_it;
};
class const_iterator
{
friend class Vertex;
public:
typedef const_iterator self_type;
typedef int value_type;
typedef int & reference;
typedef int * pointer;
typedef t_node_to_nn::iterator map_iterator;
typedef std::forward_iterator_tag iterator_category;
const_iterator( map_iterator map_it ) : _map_it( map_it ) { }
self_type operator++() { _map_it++; return *this; } // PREFIX
self_type operator++(int junk) { self_type i = *this; _map_it++; return i; } // POSTFIX
const value_type operator*() { return ( * _map_it ).first; } // Return the index "i"
const Graph::t_nn * operator->() { return & ( * _map_it ).second; } // Return a pointer to the contained t_nn.
bool operator==( const self_type& rhs ) { return _map_it == rhs._map_it; }
bool operator!=( const self_type& rhs ) { return _map_it != rhs._map_it; }
private:
map_iterator _map_it;
};
iterator begin() { _node_to_nn.begin(); }
iterator end() { _node_to_nn.end(); }
const_iterator begin() const { _node_to_nn.begin(); }
const_iterator end() const { _node_to_nn.end(); }
nn_iterator nn_begin( int i ) { assert( has_node( i ) ); return _node_to_nn[ i ].begin(); }
nn_iterator nn_end( int i ) { assert( has_node( i ) ); return _node_to_nn[ i ].end(); }
Graph() : _num_links( 0 ) {}
~Graph() { _node_to_nn.clear(); _num_links = 0; }
Graph & subgraph( std::set< int > & nodes ) {
Graph * S = new Graph();
for ( std::set< int >::iterator n_it = nodes.begin() ; n_it != nodes.end() ; n_it++ ) {
int i = ( * n_it );
assert( has_node( i ) );
for ( nn_iterator j_it = nn_begin( i ) ; j_it != nn_end( i ) ; j_it++ ) {
int j = ( * j_it );
if ( nodes.count( j ) > 0 ) { S -> add_link( i , j ); }
}
}
return ( * S );
}
int num_nodes() { return _node_to_nn.size(); }
int num_links() { return _num_links; }
int degree( int i ) { return _node_to_nn[ i ].size(); }
double avrg_degree() { return ( ( double ) 2 * num_nodes() ) / ( ( double ) _num_links ); }
bool has_node( int i ) { return _node_to_nn.count( i ) > 0; }
bool has_nn( int i , int j ) {
if ( has_node( i ) ) { return _node_to_nn[ i ].count( j ) > 0; }
return false;
}
bool has_link( int i , int j ) { return has_nn( i , j ); }
void add_node( int i ) { _node_to_nn[ i ].count( 0 ); } // Trick...
void add_link( int i , int j ) {
if ( has_link( i , j ) ) { return; }
_node_to_nn[ i ].insert( j );
_node_to_nn[ j ].insert( i );
_num_links += 1;
}
void del_link( int i , int j ) {
if ( has_link( i , j ) ) {
_node_to_nn[ i ].erase( j );
_node_to_nn[ j ].erase( i );
_num_links -= 1;
}
}
void del_node( int i ) {
iterator i_it = _node_to_nn.find( i );
for( nn_iterator j_it = i_it -> begin() ; j_it != i_it -> end() ; j_it++ ) { del_link( i , ( * j_it ) ); }
_node_to_nn.erase( i_it._map_it );
}
void clear_node( int i ) { del_node( i ); add_node( i ); } // Trick...
private:
t_node_to_nn _node_to_nn;
int _num_links;
};
std::ostream& operator<<( std::ostream& os , Graph & G );
typedef Graph::t_nn Graph_t_nn
typedef
#endif // Included_cpp_graph
The C++ .cpp file:
// cpp_graph.cpp
#include <cassert>
#include <cstddef>
#include <set>
#include <map>
#include <iostream>
#include <string>
#include <sstream>
#include "to_string_patch.h"
#include "cpp_graph.h"
std::ostream& operator<<( std::ostream& os , Graph & G ) {
os << "Graph{";
// Print nodes.
for ( Graph::iterator i_it = G.begin() ; i_it != G.end() ; i_it++ ) {
int i = ( * i_it );
os << " " << patch::to_string( i );
}
os << " |";
// Print edges.
for ( Graph::iterator i_it = G.begin() ; i_it != G.end() ; i_it++ ) {
int i = ( * i_it );
for ( Graph::nn_iterator j_it = G.nn_begin( i ) ; j_it != G.nn_end( i ) ; j_it++ ) {
int j = ( * j_it );
if ( i < j ) { os << " " + patch::to_string( i ) << ":" << patch::to_string( j ); }
}
}
os << " }"; // << std::endl;
return os;
}
// === For testing purposes ===.
/*
int main() {
Graph G;
G.add_link( 1 , 2 );
G.add_link( 1 , 3 );
G.add_link( 2 , 3 );
G.add_link( 3 , 4 );
G.add_link( 4 , 5 );
G.add_link( 4 , 6 );
G.add_link( 5 , 6 );
std::cout << G << std::endl;
G.del_link( 3 , 4 );
std::cout << G << std::endl;
G.del_node( 3 );
std::cout << G << std::endl;
G.clear_node( 2 );
std::cout << G << std::endl;
G.add_link( 100 , 101 );
std::cout << G << std::endl;
std::cout << "N = " << G.num_nodes() << " M = " << G.num_links() << std::endl;
}
*/
The cython .pxd file:
# file : graph.pxd
# === Cython cimports ===
from libcpp cimport bool
from libcpp.set cimport set as cset
from libcpp.map cimport map as cmap
from cython.operator cimport dereference as deref, preincrement as inc
# === Exposing the C++ Graph class ===
cdef extern from "cpp_graph.h":
cdef cppclass Graph:
#public:
ctypedef cset[ int ] t_nn
ctypedef cset[ int ].iterator nn_iterator
ctypedef cmap[ int , t_nn ] t_node_to_nn
cppclass iterator:
#friend class Graph;
#public:
typedef iterator self_type
typedef int value_type
typedef int & reference
typedef int * pointer
typedef t_node_to_nn::iterator map_iterator
typedef std::forward_iterator_tag iterator_category
iterator( map_iterator map_it )
self_type operator++()
self_type operator++(int junk)
value_type operator*()
Graph::t_nn * operator->()
bool operator==( const self_type & rhs )
bool operator!=( const self_type & rhs )
#private:
# map_iterator _map_it;
cppclass const_iterator:
#friend class Vertex;
#public:
typedef const_iterator self_type
typedef int value_type
typedef int & reference
typedef int * pointer
typedef t_node_to_nn::iterator map_iterator
typedef std::forward_iterator_tag iterator_category
const_iterator( map_iterator map_it )
self_type operator++()
self_type operator++(int junk)
const value_type operator*()
const Graph::t_nn * operator->()
bool operator==( const self_type& rhs )
bool operator!=( const self_type& rhs )
#private:
# map_iterator _map_it;
iterator begin()
iterator end()
const_iterator begin() const
const_iterator end() const
nn_iterator nn_begin( int i )
nn_iterator nn_end( int i )
Graph()
~Graph()
Graph & subgraph( std::set< int > & nodes )
int num_nodes()
int num_links()
int degree( int i )
double avrg_degree()
bool has_node( int i )
bool has_nn( int i , int j )
bool has_link( int i , int j )
void add_node( int i )
void add_link( int i , int j )
void del_link( int i , int j )
void del_node( int i )
void clear_node( int i )
#private:
#t_node_to_nn _node_to_nn;
#int _num_links;
std::ostream& operator<<( std::ostream& os , Graph & G )
# === Python Wrapper for the C++ Graph class ===
cdef class PyGraph:
# === Data-members ===
# Pointer to a C++ Graph object.
cdef Graph * _c_graph
# === Function-members ===
# # graph.pyx
And the cython .pyx file:
# file : graph.pyx
# === Cython cimports ===
from libcpp cimport bool
from libcpp.set cimport set as cset
from libcpp.map cimport map as cmap
from cython.operator cimport dereference as deref, preincrement as inc
# === Ctypedefs for Graph class ===
# # graph.pxd
# === Exposing the C++ Graph class ===
cdef extern from "cpp_graph2.h":
cdef cppclass Graph:
#public:
ctypedef cset[ int ] t_nn
ctypedef cset[ int ].iterator nn_iterator
ctypedef cmap[ int , t_nn ] t_node_to_nn
cppclass iterator:
#friend class Graph;
#public:
typedef iterator self_type
typedef int value_type
typedef int & reference
typedef int * pointer
typedef t_node_to_nn::iterator map_iterator
typedef std::forward_iterator_tag iterator_category
iterator( map_iterator map_it )
self_type operator++()
self_type operator++(int junk)
value_type operator*()
Graph::t_nn * operator->()
bool operator==( const self_type & rhs )
bool operator!=( const self_type & rhs )
#private:
# map_iterator _map_it;
cppclass const_iterator:
#friend class Vertex;
#public:
typedef const_iterator self_type
typedef int value_type
typedef int & reference
typedef int * pointer
typedef t_node_to_nn::iterator map_iterator
typedef std::forward_iterator_tag iterator_category
const_iterator( map_iterator map_it )
self_type operator++()
self_type operator++(int junk)
const value_type operator*()
const Graph::t_nn * operator->()
bool operator==( const self_type& rhs )
bool operator!=( const self_type& rhs )
#private:
# map_iterator _map_it;
iterator begin()
iterator end()
const_iterator begin() const
const_iterator end() const
nn_iterator nn_begin( int i )
nn_iterator nn_end( int i )
Graph()
~Graph()
Graph & subgraph( std::set< int > & nodes )
int num_nodes()
int num_links()
int degree( int i )
double avrg_degree()
bool has_node( int i )
bool has_nn( int i , int j )
bool has_link( int i , int j )
void add_node( int i )
void add_link( int i , int j )
void del_link( int i , int j )
void del_node( int i )
void clear_node( int i )
#private:
#t_node_to_nn _node_to_nn;
#int _num_links;
# === Python Wrapper for the C++ Graph class ===
cdef class PyGraph:
# === Data-members ===
# # graph.pxd
# === Function-members ===
def __cinit__( self ):
self._c_graph = new Graph()
def __dealloc__( self ):
del self._c_graph
# TODO : implement the methods for adding and deleting nodes/links.
Finally, when I attempt to compile/build this, I get the following error:
###########################################################
# setup build_ext...
###########################################################
Error compiling Cython file:
------------------------------------------------------------
...
# === Exposing the C++ Graph class ===
cdef extern from "cpp_graph2.h":
cdef cppclass Graph:
#public:
ctypedef cset[ int ] t_nn
^
------------------------------------------------------------
ExcessDegreeModel/graph.pxd:51:8: Expected an identifier, found 'ctypedef'
...
I have gotten nested definitions to work using the namespace keyword, specifying the nested declaration. Like, if you have e.g. the following in a C++ header named mystuff.hpp:
namespace MyStuff {
struct Outer {
struct Inner {
int value;
};
Inner member;
};
}
… you can encython those structures like so:
cdef extern from "mystuff.hpp" namespace "MyStuff::Outer":
cppclass Inner:
int value
cdef extern from "mystuff.hpp" namespace "MyStuff":
cppclass Outer:
Inner member
… it reads more coherently if you actually have everything in C++-land wrapped in a namespace, as written (otherwise the second cdef has no namespace in its declaration, which looks wierder IMO).
I have a number of real-world currently-working examples of this: one such example is here, another one is here.

Searching through a const std::map

I am working on one of my classes and I have come upon a stumbling block. I'll give you a sample of my source only the names of classes, methods and variable names are different, but the implementation is the same. You will see my problem/s, question/s & concern/s within the code block to the appropriate function.
MyClass.h
#ifndef MY_CLASS_H
#define MY_CLASS_H
const std::string strOne = std::string( "one" );
const std::string strTwo = std::string( "two" );
const std::string strThree = std::string( "three" );
const std::string strUnknown = std::string( "unknown" );
enum Count {
ONE,
TWO,
THREE,
UNKNOWN
};
class MyClass {
private:
const std::map<Count, const std::string> m_mCount = createCountMap();
unsigned short m_uCount;
std::vector<std::string> m_vItems;
std::multimap<const std::string, const std::string> m_mmAssociatedItems;
public:
MyClass();
MyClass( const std::string strItem1, const std::string strItem2 );
static MyClass* get();
void addItem( Count type, const std::string& strItem2 );
void addItem( const std::string& strItem1, const std::string& strItem2 );
private:
static const std::map<Count, const std::string> createCountMap();
};
#endif // MY_CLASS_H
MyClass.cpp
#include "stdafx.h"
#include "MyClass.h"
static MyClass* s_pMyClass = nullptr;
const std::map<Count, const std::string> MyClass:createCountMap() {
std::map<Count, const std::string> m;
m.insert( std::make_pair( Count::ONE, strOne ) );
m.insert( std::make_pair( Count::TWO, strTwo ) );
m.insert( std::make_pair( Count::Three, strThree ) );
m.insert( std::make_pair( Count::UNKNOWN, strUnknown ) );
return m;
} // createCountMap
MyClass* MyClass::get() {
if ( !s_pMyClass ) {
return nullptr;
}
return s_pMyClass;
} // get
MyClass::MyClass() : m_uCount( 0 ) {
m_vItems.clear();
m_mmAssociatedItems.clear();
} // MyClass
MyClass::MyClass( const std::string& strItem1, const std::string& strItem2 ) :
m_uCount( 0 ) {
addItem( strItem1, strItem2 );
} // MyClass
void MyClass::addItem( Count type, const std::string& strItem2 ) {
const std::map<Count, const std::string>::const_iterator it = m_mCount.find( type );
if ( it == m_mCount.end() ) {
// Did not find a valid item key!
// Throw Exception Here!
}
m_vItems.push_back( strItem2 );
m_mmAssociatedItems.insert( std::make_pair( it->second, m_vItems.at( m_uCount ) ) );
++m_uCount;
}
void MyClass::addItem( const std::string& strItem1, const std::string& strItem2 ) {
// I need to do a similar thing as above instead of looking through my
// const std::map at the key values for a match, with this overloaded
// function call I need to use strItem1 as the search item to see if it
// is within the contents of this map which would be the map's ->second
// value. If not throw a similar error as above otherwise once it is
// found populate my vector and multimap same as above and increment
// my count variable.
// This would logically be my next step
const std::map<Count, const std::string>::const_iterator it = m_mCount.begin();
// It Is Within This For Loop That It Fails To Compile! It
// Fails At The it++ Part! Is There A Way Around This? Or
// Am I Missing Something Simple?
for ( ; it != m_mCount.end(); it++ ) {
// If strItem1 == it->second && it != m_mCount.end()
// found it, add items, if not throw error
}
m_vItems.push_back( strItem2 );
m_mmAssociatedItems.insert( std::make_pair( strItem1, strItem2 ) );
++m_uCount;
}
In my source, it is this second function which is more important then the first! Any Help or suggestions is very much appreciated.
const std::map<Count, const std::string>::const_iterator it = m_mCount.begin();
The first const should be removed. Otherwise it cannot be moved forward, and you cannot iterate through m_mCount.