Faced with the problem, which heard only within the gcc compiler. I have been programming in Visual Studio 2013 (update 3).
I need to create some objects in the some right thread.
Also, there is a need to be able to pass a function of their creation.
This code
class Object1;
class Object2;
class MyClass
{
public:
std::function<Object1*( const std::vector<int>& )> creatorForObject1() const;
std::function<Object2*( int, double )> creatorForObject2() const;
private:
// exec 'handler' in other thread when there is a possibility
void execInRightThread( std::function<void()> handler ) const;
// need be called in right thread
Object1& craeteObject1( const std::vector<int>& param );
Object2& craeteObject2( int param1, double param2 );
template<class TObject, class ...TParams>
std::function<TObject*( TParams... )> creatorForObject( TObject&( MyClass::*creator )( TParams... ) ) const;
};
template<class TObject, class ...TParams>
std::function<TObject*( TParams... )> MyClass::creatorForObject( TObject&( MyClass::*creator )( TParams... ) ) const
{
return [ this, &creator ]( TParams... params )
{
TObject* result = nullptr;
MyClass& me = *const_cast<MyClass*>( this );
me.execInRightThread( [ &me, &result, &creator, ¶ms... ]()
{
result = &( me.*creator )( params... );
} );
while( result == nullptr ); // ugliness
return result;
};
}
std::function<Object1*( const std::vector<int>& )> MyClass::creatorForObject1() const
{
return creatorForObject( &MyClass::craeteObject1 );
}
std::function<Object2*( int, double )> MyClass::creatorForObject2() const
{
return creatorForObject( &MyClass::craeteObject2 );
}
report an errors
error C3521: 'params' is not a parameter pack
error C3546: '...' : there are no parameter packs available to expand
error C2065: 'params' : undeclared identifier
at the line
me.execInRightThread( [ &me, &result, &creator, ¶ms... ]()
Please, help.
Thanks in advance.
You could try:
template<class TObject, class ...TParams>
std::function<TObject*( TParams... )> MyClass::creatorForObject( TObject&( MyClass::*creator )( TParams... ) ) const
{
return [ this, &creator ]( TParams... params )
{
TObject* result = nullptr;
MyClass& me = *const_cast<MyClass*>( this );
me.execInRightThread( [ & ]()
{
result = &( me.*creator )( params... );
} );
while( result == nullptr ); // ugliness
return result;
};
}
Maybe you should capture by value though...
This works if the inner lambda make a separate function, but I do not understand why does not work above written.
class MyClass
{
...
private:
template<class TObject, class ...TParams>
std::function<TObject*( TParams... )> creatorForObject( TObject&( MyClass::*creator )( TParams... ) ) const;
template<class TObject, class ...TParams>
TObject* temporaryCreator( TObject&( MyClass::*creator )( TParams... ), TParams... params );
};
template<class TObject, class ...TParams>
std::function<TObject*( TParams... )> MyClass::temporaryCreator( TObject&( MyClass::*creator )( TParams... ), TParams... params )
{
TObject* result = nullptr;
execInRightThread( [ this, &result, creator, ¶ms... ]()
{
result = &( me.*creator )( params... );
} );
while( result == nullptr ); // ugliness
return result;
}
template<class TObject, class ...TParams>
std::function<TObject*( TParams... )> MyClass::creatorForObject( TObject&( MyClass::*creator )( TParams... ) ) const
{
MyClass& me = *const_cast<MyClass*>( this );
return [ &me, creator ]( TParams... params )
{
return temporaryFunction<TObject, TParams...>( creator, params... );
};
}
Related
I want to simulate that an access to a file mapped into memory results in an access violation when the file is being delete while it is accessed through a mapping. That's my current code:
#include <Windows.h>
#include <iostream>
#include <atomic>
using namespace std;
using XHANDLE = unique_ptr<void, decltype([]( void *h ) { h && h != INVALID_HANDLE_VALUE && CloseHandle( (HANDLE)h ); })>;
using XMAP_VIEW = unique_ptr<void, decltype([]( void *p ) { p && UnmapViewOfFile( p ); })>;
template<typename Fn, typename Filter, typename Handler>
requires requires( Fn fn, Filter filter, EXCEPTION_POINTERS *pEp, Handler handler ) { { fn() }; { filter( pEp ) } -> same_as<LONG>; { handler() }; }
void seh_encapsulate( Fn fn, Filter filter, Handler handler );
int wmain( int argc, wchar_t **argv )
{
if( argc < 2 )
return EXIT_FAILURE;
XHANDLE xhFile( CreateFileW( argv[1], GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_DELETE, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL ) );
if( xhFile.get() == INVALID_HANDLE_VALUE )
return EXIT_FAILURE;
LARGE_INTEGER liFileSize;
if( !GetFileSizeEx( xhFile.get(), &liFileSize ) || liFileSize.QuadPart > (size_t)-1 )
return EXIT_FAILURE;
XHANDLE xhMappging( CreateFileMapping( xhFile.get(), nullptr, PAGE_READONLY, 0, 0, nullptr ) );
if( !xhMappging.get() )
return EXIT_FAILURE;
XMAP_VIEW mapView( MapViewOfFile( xhMappging.get(), FILE_MAP_READ, 0, 0, 0 ) );
if( !mapView.get() )
return EXIT_FAILURE;
atomic_char
*pa = (atomic_char *)mapView.get(),
*paEnd = pa + (size_t)liFileSize.QuadPart;
seh_encapsulate(
[&]()
{
for( ; ; )
for( atomic_char *paScn = pa; paScn != paEnd; ++paScn )
(void)paScn->load( memory_order_relaxed );
},
[&]( EXCEPTION_POINTERS *pEp ) -> LONG
{
if( pEp->ExceptionRecord->ExceptionCode != EXCEPTION_IN_PAGE_ERROR )
return EXCEPTION_CONTINUE_SEARCH;
if( pEp->ExceptionRecord->NumberParameters < 2 )
return EXCEPTION_CONTINUE_SEARCH;
void *where = (void *)pEp->ExceptionRecord->ExceptionInformation[1];
if( where < pa || where >= paEnd )
return EXCEPTION_CONTINUE_SEARCH;
return EXCEPTION_EXECUTE_HANDLER;
},
[]()
{
cout << "I/O error" << endl;
} );
}
template<typename Fn, typename Filter, typename Handler>
requires requires( Fn fn, Filter filter, EXCEPTION_POINTERS *pEp, Handler handler ) { { fn() }; { filter( pEp ) } -> same_as<LONG>; { handler() }; }
void seh_encapsulate( Fn fn, Filter filter, Handler handler )
{
__try
{
fn();
}
__except( filter( GetExceptionInformation() ) )
{
handler();
}
}
"Unfortunately" I can delete the file but the clusters which occupied the file on the disk are retained until the mapping is closed.
Do you have any idea how I could make the clusters being unmapped so that my experiment will work ?
Aside from that the above code nicely shows how to have Structured Exception Handling "in" a function with stack-unwinding.
My intent was simply to find out if I/O errors occuring with a memory mapped file could be catched. My final idea was to copy a large file to an USB stick, unplug und plug it so that the cached data with that stick is flushed, then run the above program with that and unplug the stick while the code is running. And the result was like I expected: the I/O error results in an access violation which is caught by the above SEH handler.
I am working on a factory that can register and create classes with a different set a parameter types and numbers. I search over the internet and I managed to create this class:
template< typename Key, typename BaseClass >
class Factory {
static_assert( std::has_virtual_destructor< BaseClass >::value,
"BaseClass must have a virtual destructor" );
public:
template< typename DerivedClass, typename ... Args >
void register_creator( const Key& key )
{
static_assert( std::is_base_of< BaseClass, DerivedClass >::value,
"DerivedClass must be a subclass of BaseClass" );
static_assert( std::is_constructible< DerivedClass, Args... >::value,
"DerivedClass must be constructible with Args..." );
creators_.emplace(
CreatorKey { key, create_function_type_index< Args... >() },
reinterpret_cast< CreateFunc< > >( create_function_impl<
DerivedClass, Args... > ) );
}
template< typename ... Args >
std::unique_ptr< BaseClass > create(
const Key& key,
Args&&... args ) const
{
auto creator = creators_.find(
{ key, create_function_type_index< Args... >() } );
if( creator != creators_.end() ) {
return reinterpret_cast< CreateFunc< Args... > >( creator->second )(
std::forward< Args>( args )... );
} else {
return {};
}
}
private:
template< typename ... Args >
static std::type_index create_function_type_index()
{
return {typeid( CreateFunc<Args...> )};
}
template< typename DerivedClass, typename ... Args >
static std::unique_ptr< BaseClass > create_function_impl(
const Args&... args )
{
return std::unique_ptr< BaseClass > { new DerivedClass {
std::forward< const Args& >( args )... } };
}
template< typename ... Args >
using CreateFunc = typename std::add_pointer< std::unique_ptr< BaseClass >( const Args&... ) >::type;
using CreatorKey = std::pair< Key, std::type_index >;
std::map< CreatorKey, CreateFunc< > > creators_;
};
My goal is to be able to run this kind of code:
class ___A___ {};
class ___B___ {};
class ___Base___ {
public:
virtual ~___Base___() = default;
protected:
___Base___( ___A___ a, ___B___ b ) : a_( a ), b_( b ) {
}
protected:
___A___ a_;
___B___ b_;
};
class ___Derived___: public ___Base___ {
public:
___Derived___( ___A___& a, ___B___& b ) : ___Base___( a, b ) {
}
};
class ___Derived2___: public ___Base___ {
public:
___Derived2___( ___A___ a, ___B___ b ) : ___Base___( a, b ) {
}
};
class ___Derived3___: public ___Base___ {
public:
___Derived3___( ___A___& a, ___B___ b ) : ___Base___( a, b ) {
}
};
Factory< std::string, ___Base___ > factory;
factory.register_creator< ___Derived___, ___A___ &, ___B___& >( "Derived" );
factory.register_creator< ___Derived2___, ___A___, ___B___ >( "Derived2" );
factory.register_creator< ___Derived3___, ___A___ &, ___B___ >( "Derived3" );
___A___ a;
___B___ b;
auto D = factory.create( "Derived", a, b );
auto D2 = factory.create( "Derived2", a, b );
auto D3 = factory.create( "Derived3", a, b );
The registers works perfectly for both reference and value parameters but I cannot manage to instiate them using the creators. During my debugging, I saw that all the parameters where given by reference and never by value.
Using deduced types like this:
auto D = factory.create( "Derived", a, b );
in order to do a cast is something you should never do. The type deduces here will be basically &decltype(a) (not decltype(&a); a reference to the type of a, not the type of a pointer to a).
return reinterpret_cast< CreateFunc< Args... > >( creator->second )(
std::forward< Args>( args )... );
this requires exact type matching. When this matches the type, it happens accidentally more than anything.
To do what you want, you have a whole pile of work to do, even if you want to only support "exact matching" of types.
Given a type T, there are a number of ways it can be used as an argument to a function.
It can be moved into the argument: T&&. A "sink" argument.
It can be duplicated into the argument: T. A "value" argument.
It can be referred to by the argument but guaranteed not to be modified, T const&. An "in" argument.
It can be referred to by the argument, and possibly modified, T&. An "in/out" argument.
The other options are possible, but are less interesting.
At the point where you register your function, you have to work out both the type T and which of the 4 above cases you are dealing with.
Then, at the point where you want to call your function, you have to work out the type T and which of the above 4 you support.
Then you have to inject the code to glue the incoming argument to the function to call.
We can simplify this by having fewer kinds of argument than the above 4 relatively commonly used in C++ code. For example, "value" can usually replace "sink" at the cost of one extra std::move construction.
If you don't want the caller to have to know exactly what kind of protocol the called type needs, you have to type erase the details.
Imagine an adapter:
template<class T>
struct arg_adapter;
it can be constructed from a T&&, T const& or T&. When it is constructed, it records a void* pointer to the incoming object, and which of the 3 categores of type it was passed.
It has a .get<U> method, where U can be any of T&&, T const& or T&. It checks if the .get is compatible; if it is, it casts the void* stored within to remove_reference_t<U>*, dereferences it, and static_cast<U>'s it.
If it fails, it throws an exception or calls exit(-1) or somesuch.
Now you store std::function< Out(arg_adapter<std::decay_t<Args>>...) > instead of std::function< Out(Args...) >.
You know, something like this:
template
struct tag_t {};
template<class Dest>
using p_getter = Dest(*)(void*);
template<class T>
struct arg_vtable {
p_getter<T&> ref = 0;
p_getter<T const&> cref = 0;
p_getter<T> value = 0;
p_getter<T&&> move = 0;
};
template<class Dest, class Src>
p_getter<Dest> make_getter() {
return [](void* ptr)->Dest{
return (Src&&)(*static_cast<std::decay_t<Src>*>(ptr));
};
}
template<class T>
arg_vtable<T> make_arg_vtable( tag_t<T const&> ) {
return {
0,
make_getter<T const&, T const&>(),
make_getter<T, T const&>(),
0
};
}
template<class T>
arg_vtable<T> make_arg_vtable( tag_t<T&> ) {
return {
make_getter<T&, T&>(),
make_getter<T const&, T&>(),
make_getter<T, T&>(),
0
};
}
template<class T>
arg_vtable<T> make_arg_vtable( tag_t<T&&> ) {
return {
0,
make_getter<T const&, T&&>(),
make_getter<T, T&&>(),
make_getter<T&&, T&&>(),
};
}
template<class T>
arg_vtable<T> make_arg_vtable( tag_t<T const&&> ) {
return make_arg_vtable( tag_t<T const&>{} );
}
template<class T, class U>
arg_vtable<T> make_arg_vtable( tag_t<T volatile&&> ) {
return make_arg_vtable( tag_t<T&&>{} );
}
template<class T, class U>
arg_vtable<T> make_arg_vtable( tag_t<T volatile&> ) {
return make_arg_vtable( tag_t<T&>{} );
}
template<class T, class U>
arg_vtable<T> const* get_arg_vtable( tag_t<U> tag ) {
static const arg_vtable<T> retval = make_arg_vtable<T>(tag);
return &retval;
}
template<class T>
struct arg_adapter {
arg_vtable<T> const* vtable = 0;
void* pvoid = 0;
template<class U>
arg_adapter( U&& u ):
vtable( get_arg_vtable<T>( tag_t<U&&>{} ) ),
pvoid( (void*)std::addressof(u) )
{}
T get(tag_t<T>) {
if (!vtable->value) throw std::invalid_argument("value");
return vtable->value(pvoid);
}
T&& get(tag_t<T&&>) {
if (!vtable->move) throw std::invalid_argument("move");
return vtable->move(pvoid);
}
T& get(tag_t<T&>) {
if (!vtable->ref) throw std::invalid_argument("ref");
return vtable->ref(pvoid);
}
T const& get(tag_t<T const&>) {
if (!vtable->ref) throw std::invalid_argument("cref");
return vtable->cref(pvoid);
}
};
template<class R, class...Args>
using adapt_function = std::function< R(arg_adapter<std::decay_t<Args>>...) >;
template<class R, class...Args, class F>
adapt_function<R, Args...> adapt_args( F&& f ) {
return [f=std::forward<F>(f)](arg_adapter<std::decay_t<Args>>... args)->R{
return f( args.get( tag_t<Args>{} )... );
};
}
using func_token = std::shared_ptr<void>;
template<class R, class...Args>
R invoke_token( func_token f, Args&&... args ) {
auto const* pf = static_cast<adapt_function<R, Args...>*>(f.get());
return (*pf)( std::forward<Args>(args)... );
}
template<class R>
struct factories {
std::map< std::string, func_token > funcs;
template<class...Args, class F>
void add( std::string s, F&& f ) {
funcs[s] = std::make_shared<adapt_function<R,Args...>>(adapt_args<R,Args...>(std::forward<F>(f)));
}
template<class...Args>
R invoke( std::string s, Args&&... args ) {
auto it = funcs.find(s);
if (it==funcs.end()) throw std::invalid_argument("s");
return invoke_token<R>( it->second, std::forward<Args>(args)... );
}
};
Live example
It needs forwarding overloads to arg_adapter::get like the ones for make_arg_vtable I suspect.
Overall, I think this is a bad idea, because the invokers only handle cv conversion and nothing else. Anything else causes a crash or other undefined behavior.
In my app I would like to pass in a parameter pack over a legacy function signature, and change the values. Here is code that illustrates my question with my attempts as comments:
#include <tuple>
#include <cassert>
void LegacySignature( void* param );
template< typename... ArgsT >
// using ???; // attempt: can 'template alias' or 'using declaration' make the pack's type visible so I can use it inside the LegacyFunction?
void MyFunc( ArgsT&... args )
{
auto userArgsTuple = std::forward_as_tuple< ArgsT&... >( args... );
LegacySignature( &userArgsTuple );
}
void LegacySignature( void* param )
{
// auto userArgsTuple = reinterpret_cast<???>( param ); // attempt: how can I get the parameter pack's type declared so I can use it here?
// do something with the params like change num to 44 and tf to true;
//userArgsTuple->num = 44; // desired functionality
//userArgsTuple->tf = true; // desired functionality
}
int main()
{
int num { 33 };
bool tf { false };
MyFunc( num, tf );
assert( num == 44 && tf == true );
return 0;
}
Is there a way to make the parameter pack a declarable lvalue?
I'm assuming what you want is a function pointer to your legacy signature.
Here is a C++11 approach.
template<class Sig, class F>
struct magic_callback_t;
template<class R, class...Args, class F>
struct magic_callback_t<R(Args...), F> {
F f;
void* pvoid() const { return this; }
using result_sig = R(*)(void*, Args...);
result_sig pfunc() const {
return [](void* pvoid, Args...args)->R{
auto* self = static_cast<magic_callback_t*>(pvoid);
return (self->f)(std::forward<Args>(args)...);
};
}
};
template<class Sig, class F>
magic_callback_t<Sig, F> magic_callback( F&& f ) {
return {std::forward<F>(f)};
}
Now we just do this:
auto callback = magic_callback( [&](){
// use whatever as if we where in the enclosing scope
});
void(*)(void*) legacy_ptr = callback.pfunc();
legacy_ptr( callback.pvoid() );
will call the lambda you passed to magic_callback.
If you want to store stuff as a tuple, you can. Just capture the tuple in the lambda, then use std::get to access it in the body of the lambda. Use mutable if you want it to be mutable.
The code below fixes the sample code so that it answers the question as to how to pass a parameter pack over a legacy function signature using forward_as_tuple.
#include <tuple>
#include <cassert>
#include <memory>
#include <functional>
#define ARGSET int, bool
void LegacySignature( long* param ); // ie, LPARAM
template< typename... ArgsT >
struct MyParams
{
MyParams( ArgsT... args ) : rvalRefs { std::forward_as_tuple( args... ) } {} // The resulting forward_as_tuple tuple has rvalue reference data members
std::tuple< ArgsT... > rvalRefs;
};
void LegacySignature( long* legSigParam )
{
auto userArgsTuple( reinterpret_cast< MyParams< ARGSET >* >( legSigParam ) );
// do something with the params like change num to 44 and tf to true;
std::get< 0 >( userArgsTuple->rvalRefs ) = 44; // index types can probably be worked out using enums
std::get< 1 >( userArgsTuple->rvalRefs ) = true;
}
int main()
{
int num { 33 };
bool tf { false };
MyParams< ARGSET > myParams( num, tf );
std::unique_ptr< MyParams< ARGSET > > legSigParamPtr = std::make_unique< MyParams< ARGSET > >( myParams );
LegacySignature( ( long* )legSigParamPtr.get() );
assert( std::get< 0 >( legSigParamPtr->rvalRefs ) == 44 && std::get< 1 >( legSigParamPtr->rvalRefs ) == true );
return 0;
}
Im new to C++ and I'm getting an error which I've never seen before. I am attempting to search by a backtracking algorithm that uses a hash table (open hashing).
Before I make a recursive call, I'm searching the hash table to see if the current position has been searched before (and has failed) and then inserting vector of ints "B" into the hash table when the recursive call returns false so that future search for the same position can be avoided.
Heres my function in my program calling file to hash:
bool open_hash_solve (vector<int> B, vector<Move> & MS, vector<Move> & TMS, OpenHashTable<vector<int>> & H) {
if (solved(B))
return true;
vector<Move> curr = currentMoves(B, TMS);
for (int m = 0; m < curr.size(); m++) {
vector<int> moveMade = makeMove(B, curr[m]);
if (!H.contains(moveMade)){
if (open_hash_solve(moveMade, MS, TMS, H)){
MS.insert(MS.begin(), curr[m]);
return true;
}
else
H.insert(moveMade);
}
}
return false;
}
Header file Separate Chaining from the textbook:
#ifndef SEPARATE_CHAINING_H
#define SEPARATE_CHAINING_H
#include <vector>
#include <list>
#include <string>
#include <algorithm>
#include <functional>
using namespace std;
int nextPrime( int n );
// SeparateChaining Hash table class
//
// CONSTRUCTION: an approximate initial size or default of 101
//
// ******************PUBLIC OPERATIONS*********************
// bool insert( x ) --> Insert x
// bool remove( x ) --> Remove x
// bool contains( x ) --> Return true if x is present
// void makeEmpty( ) --> Remove all items
template <typename HashedObj>
class OpenHashTable
{
public:
explicit OpenHashTable( int size = 101 ) : currentSize{ 0 }
{ theLists.resize( 101 ); }
bool contains( const HashedObj & x ) const
{
auto & whichList = theLists[ myhash( x ) ];
return find( begin( whichList ), end( whichList ), x ) != end( whichList );
}
void makeEmpty( )
{
for( auto & thisList : theLists )
thisList.clear( );
}
bool insert( const HashedObj & x )
{
auto & whichList = theLists[ myhash( x ) ];
if( find( begin( whichList ), end( whichList ), x ) != end( whichList) )
return false;
whichList.push_back( x );
// Rehash; see Section 5.5
if( ++currentSize > theLists.size( ) )
rehash( );
return true;
}
bool insert( HashedObj && x )
{
auto & whichList = theLists[ myhash( x ) ];
if( find( begin( whichList ), end( whichList ), x ) != end( whichList ) )
return false;
whichList.push_back( std::move( x ) );
// Rehash; see Section 5.5
if( ++currentSize > theLists.size( ) )
rehash( );
return true;
}
bool remove( const HashedObj & x )
{
auto & whichList = theLists[ myhash( x ) ];
auto itr = find( begin( whichList ), end( whichList ), x );
if( itr == end( whichList ) )
return false;
whichList.erase( itr );
--currentSize;
return true;
}
private:
vector<list<HashedObj>> theLists; // The array of Lists
int currentSize;
void rehash( )
{
vector<list<HashedObj>> oldLists = theLists;
// Create new double-sized, empty table
theLists.resize( nextPrime( 2 * theLists.size( ) ) );
for( auto & thisList : theLists )
thisList.clear( );
theLists.resize( nextPrime( 2 * theLists.size( ) ) );
for( auto & thisList : theLists )
thisList.clear( );
// Copy table over
currentSize = 0;
for( auto & thisList : oldLists )
for( auto & x : thisList )
insert( std::move( x ) );
}
size_t myhash( const HashedObj & x ) const
{
static hash<HashedObj> hf; ***** ERROR HERE *****
return hf( x ) % theLists.size( );
}
};
#endif
My Error:
SeparateChaining.h: In instantiation of ‘size_t OpenHashTable<HashedObj>::myhash(const HashedObj&) const [with HashedObj = std::vector<int>; size_t = long unsigned int]’:
SeparateChaining.h:33:44: required from ‘bool OpenHashTable<HashedObj>::contains(const HashedObj&) const [with HashedObj = std::vector<int>]’
movetest1.cpp:107:29: required from here
SeparateChaining.h:106:34: error: ‘std::hash<std::vector<int> > hf’ has incomplete type
static hash<HashedObj> hf;
^
How do I fix this??
Let me know if my description doesn't make sense or needs clarity. Thanks in advance!
The reason is that std::hash is not defined for std::vector except std::vector<bool>. It's defined only for basic types and select library types. You have to implement your own hashing algorithm.
Regarding your last comment, hash( x ) is invalid code since std::hash is a class template, not a function template.
You also can't write your own specialization for std::hash<std::vector<int>> since std::vector<int> is not a user-defined type.
Appropriate solution would be in the style of C++ standard library - OpenHashTable should allow its user to specify hashing algorithm:
template<typename HashedObj, typename Hash = std::hash<HashedObj>>
class OpenHashTable {
// ...
size_t myhash(const HashedObj& x) const {
static Hash hf;
return hf(x) % theLists.size();
}
};
So you can use it as follows:
struct my_vector_int_hash {
size_t operator()(const std::vector<int>& v) const {
// your code here
}
};
OpenHashTable<std::vector<int>, my_vector_int_hash> hashtable;
Update: as long as discussion arose about whether you can specialize std::hash<std::vector<int>>, here is why you are not allowed to do it.
[namespace.std]/1 says:
The behavior of a C++ program is undefined if it adds declarations or definitions to namespace std or to a namespace within namespace std unless otherwise specified. A program may add a template specialization for any standard library template to namespace std only if the declaration depends on a user-defined type and the specialization meets the standard library requirements for the original template and is not explicitly prohibited.
std::vector<int> is not a user-defined type, nor it depends on any user-defined type, so such specialization is illegal and leads to undefined behavior.
Is there any simple way to tell if UNC path points to a local machine.
I found the following question SO
Is there any WIN32 API that will do the same?
#include <windows.h>
#include <WinSock.h>
#include <string>
#include <algorithm>
#pragma comment(lib, "wsock32.lib")
using namespace std;
std::wstring ExtractHostName( const std::wstring &share )
{
if (share.size() < 3 )
return L"";
size_t pos = share.find( L"\\", 2 );
wstring server = ( pos != string::npos ) ? share.substr( 2, pos - 2 ) : share.substr( 2 );
transform( server.begin(),server.end(), server.begin(), tolower);
return server;
}
bool IsIP( const std::wstring &server )
{
size_t invalid = server.find_first_not_of( L"0123456789." );
bool fIsIP = ( invalid == string::npos );
return fIsIP;
}
bool IsLocalIP( const std::wstring &ipToCheck )
{
if ( ipToCheck == L"127.0.0.1" )
return true;
WORD wVersionRequested;
WSADATA wsaData;
wVersionRequested = MAKEWORD( 1, 1 );
if ( WSAStartup( wVersionRequested, &wsaData ) != 0 )
return false;
bool fIsLocal = false;
char hostName[255];
if( gethostname ( hostName, sizeof(hostName)) == 0 )
{
PHOSTENT hostinfo;
if(( hostinfo = gethostbyname(hostName)) != NULL )
{
for (int i = 0; hostinfo->h_addr_list[i]; i++)
{
char *ip = inet_ntoa(*( struct in_addr *)hostinfo->h_addr_list[i]);
wchar_t wcIP[100]={0};
::MultiByteToWideChar(CP_ACP, 0, ip, -1, wcIP, _countof(wcIP));
if (ipToCheck == wcIP)
{
fIsLocal = true;
break;
}
}
}
}
WSACleanup();
return fIsLocal;
}
bool IsLocalHost( const std::wstring &server )
{
if (server == L"localhost")
return true;
bool fIsLocalHost = false;
wchar_t buffer[MAX_PATH]={0};
DWORD dwSize = _countof(buffer);
BOOL fRet = GetComputerName( buffer, &dwSize );
transform( buffer, buffer + dwSize, buffer, tolower);
fIsLocalHost = ( server == buffer );
return fIsLocalHost;
}
bool ShareIsLocal( const std::wstring &share )
{
wstring server = ExtractHostName( share );
bool fIsIp = IsIP( server );
if ( fIsIp )
return IsLocalIP( server );
else
return IsLocalHost( server );
}