Parameter pack expansion fails - visual-studio

Consider the following simplified C++ code:
template <typename ... TEventArgs>
struct Event
{
// ...
};
template <typename T>
struct Parameter
{
using Type = T;
// ...
};
template <typename ... Parameters>
struct Command
{
Event<typename Parameters::Type...> Invoked;
};
int main()
{
Command<Parameter<int>, Parameter<float>> c;
}
The Visual Studio C++ compiler (November 2013 CTP, Visual Studio 2013 Update 1) produces the following error:
source.cpp(17): error C3546: '...' : there are no parameter packs available to expand
Mingw 4.8.1. on the other hand compiles the code without any problems. Apparently, the Visual Studio compiler has a bug that prevents it from expanding the parameter pack when the expression involves accessing a type of the variadic parameters. Other expansions work, though. For instance, Event<std::vector<Parameters>...> Invoked; compiles successfully or you could even successfully access static members to call a variadic function like this in Command's constructor: SomeVariadicFunc(Parameters::SomeStaticFunc()...);.
So, the questions are:
1) Which compiler is wrong: Visual Studio or mingw? Although I don't see anything that would prevent the typename Parameters::Type parameter pack expansion from working, I'm not 100% sure it's valid C++.
2) Is there a work around? Basically, I would have to perform a projection from a "sequence" of Parameters to a "sequence" of Parameters::Type. Is that possible? I tried to construct that list using a recursive struct but I could only come up with something like myStruct<type1, mystruct<type2, mystruct<type3, ...>>>, which is not what I need.
Thank you for your help.

Yakk was able to come up with a workaround for the problem in the comments above. The final version that compiles perfectly with both Visual Studio an mingw is the following:
template <typename ... TEventArgs>
struct Event
{
// ...
};
template <typename T>
struct Parameter
{
using Type = T;
// ...
};
template <typename ... Parameters>
struct Command
{
private:
// Workaround for the Visual Studio bug
template<typename T> struct ExpandArgs
{
typedef typename T::Type Type;
};
public:
Event<typename ExpandArgs<Parameters>::Type...> Invoked;
};
int main()
{
Command<Parameter<int>, Parameter<float>> c;
}

Related

Error during template substitution reported by compiler

I'm seeing a build error which is correct, but something that I would expect to be ignored due to the Substitution Failure Is Not An Error rule:
C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\include\vector(895): error C3699: '&&': cannot use this indirection on type 'System::String ^'
RemoteWrapper.cpp(41): note: see reference to class template instantiation 'std::vector<System::String ^,std::allocator<_Ty>>' being compiled
with
[
_Ty=System::String ^
]
C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\include\vector(918): error C3699: '&&': cannot use this indirection on type 'System::String ^'
Here's the code which the error mentions:
std::string nativeString;
String^ clrString = clr_cast<String^>(nativeString);
Here are the clr_cast templates:
template<typename TReturn, typename TSource>
TReturn clr_cast(TSource value)
{
return (TReturn)value;
}
template<typename TReturn, typename TSource, typename = std::enable_if<!std::is_same<TReturn, TSource>>::value>
std::vector<TReturn> clr_cast(array<TSource>^ value)
{
[iterate and cast]
}
template<typename T>
std::vector<T> clr_cast(array<T>^ value)
{
[memcpy]
}
template<typename TReturn, typename TSource, typename = std::enable_if<!std::is_same<TReturn, TSource>>::value>
array<TReturn>^ clr_cast(std::vector<TSource> value)
{
[iterate and cast]
}
template<typename T>
array<T>^ clr_cast(std::vector<T> value) // this is the problematic function
{
[memcpy]
}
template<> std::string clr_cast(System::String^ value);
template<> System::String^ clr_cast(std::string value);
The compiler is trying to instantiate the function to which I added a comment and it's correct that it fails to do so. What I don't understand is that if I remove it then the compiler will select the correct function (the specialisation right at the end of the header) and continue happily onward.
It seems to me that the error I'm seeing is occurring during substitution, and that the compiler should therefore silently discard the std::vector<T> candidate and fall back on the specialisation. Why is this not happening?
This was happening because SFINAE only applies to the "immediate context", i.e. the template parameter itself.
The error can be turned into a substitution failure by moving the problematic instantiation into the template parameters, like this:
template<typename T, typename = T&&>
array<T>^ clr_cast(std::vector<T> value)
function
{
[memcpy]
}
The code now compiles successfully, and the appropriate clr_cast overload is selected.

How to elegantly restrict a template argument to be a `<Certain_Class<AnyT>>`?

How to restrict a template argument of Wrapper to be a Wrapper<Any,MyArray<AnyT>> elegantly?
Don't break content assist (Visual Studio).
High readability. Not use a hacky approach.
For some reasons, most solution love to hack.
Make it obvious at the very first line by using C++ syntax rule. (not just green comment)
As far as I know, there are many solutions, but every solution doesn't meet the criteria.
Workaround 1 (template specialization, fail 1)
template<class T> class MyArray{};
template<class T,class T2> class Wrapper;
template<class T,class T2> class Wrapper<T,MyArray<T2>>{
using Test=int;
};
class B{};
class C{};
int main() {
Wrapper<C,MyArray<B>> wrapper;
return 0;
}
This code is modified from https://stackoverflow.com/a/43518221 (#max66).
Context clue / syntax highlighting of IDE will be confused.
In my case, it marks some correct types as error e.g. :-
class ShowError : public Wrapper<B,MyArray<C>>{
Test n=0; //<-- unknown "Test" (intellisense)
};
Workaround 2 (some hacky field/typedef, fail 2)
template<class T> class MyArray{
public: using MyArrayT=T;
};
template<class T,class T2> class Wrapper{
public: using myT=typename T2::MyArrayT;
//^ assert at compile time
};
This idea come from a comment in https://stackoverflow.com/a/43518295 (#Jarod42)
The class declaration doesn't mention about MyArray, it just uses a hacky (less readable) way (MyArrayT) to enforce that T2 is MyArray.
Workaround 3 (base class, fail 2)
class MyArrayBase{};
template<class T> class MyArray : public MyArrayBase{ };
template<class T,class T2> class Wrapper{
//check something around MyArrayBase *object = new T2();
// or "is_base_of"
};
The code is modified from Restrict C++ Template Parameter to Subclass and C++ templates that accept only certain types.
It has same disadvantage as workaround 2.
It is not obvious for common user.
Workaround 4 (SNIFAE, fail 1)
By adding std::enable_if on the template class declaration (Wrapper), I can get a working hack.
Unfortunately, content assist hate it.
Reference
Here are the other links that I read :-
http://www.informit.com/articles/article.aspx?p=376878 (template template parameter)
restrict a template function, to only allow certain types (not related to template type as a parameter)
You can write a custom type trait is_specialization, as follows:
template<class Type, template<class...> class Template>
struct is_specialization
: std::false_type {};
template<template<class...> class Template, class... TArgs>
struct is_specialization<Template<TArgs...>, Template>
: std::true_type {};
Then you just need to static_assert that is_specialization is true for the given template argument:
template<class T,class T2>
class Wrapper {
static_assert(is_specialization<T2, MyArray>::value, "T2 must be a specialization of MyArray");
};

VS2012 complains when using +[]{} sorcery

I want automatic deduction of the arguments of a templated function which accepts a function, while using lambdas. This Example shows some of my options:
template <class T>
void foo(void (*func)(T)) {
T val;
// do something with val and func...
}
int main() {
auto pfunc0 = [] (int) { /*...*/ };
void (*pfunc1)(int) = [] (int) { /*...*/ };
auto* pfunc2 = +[] (int) { /*...*/ };
foo(pfunc0); // not ok
foo<int>(pfunc0); // ok, but redundant
foo(pfunc1); // ok, but redundant
foo(pfunc2); // ok
}
pfunc2 uses a trick I learned here: Obtaining function pointer to lambda?. So actually I should be happy with the pfunc2 case as it is concise and non repeating code, unfortunately the Visual C++ 2012 IDE complains it was erroneous code even though it compiles just fine.
Are there any workarounds or recommendations for this problem?
IDE error messages:
In the "auto* pfunc2" line: The IDE underlines 'auto' and says
Error: cannot deduce 'auto' type
also it underlines '[' where it complains
Error: more than one conversion function from "lambda[]void (int)->void" to a build-in type applies:
function "lambda[]void (int)->void::operator void (*)(int)() const"
function "lambda[]void (int)->void::operator void (*)(int)() const"
function "lambda[]void (int)->void::operator void (*)(int)() const"
This is related to this bug (closed as "by design"). VC++ supports several calling conventions on x86 and lambdas with empty capture lists provide conversions to them all. That's why there's ambiguity.
Unfortunately, there's no workaround listed that you haven't already tried.
By the way, this bug is listed as fixed in Visual C++ 2015 Update 2

where should I put the specialized std::hash for user defined type

I searched many pages, and I think I have known how to write the std::hash. But I don't know where to put it.
An example is presented here http://en.cppreference.com/w/cpp/utility/hash .
However, I defined my type Instance in namespace ca in file instance_management.h. I want to use unordered_set<Instance> in the same file in another class InstanceManager. So I write the following code:
namespace std
{
template <> struct hash<ca::Instance>
{
size_t operator()(const ca::Instance & instance) const
{
std::size_t seed = 0;
// Some hash value calculation here.
return seed;
}
};
} // namespace std
But where should I put it? I tried many locations but all failed.
I am using visual studio 2013. I tried to put the previous code in some locations but all failed to compile it.
// location 1
namespace ca
{
class Instance {...}
class InstanceManager
{
// ... some other things.
private unordered_set<Instance>;
}
}
// location 2
There are several ways.
Specializing std::hash
In your code make sure that your std::hash<Instance> specialization is preceded immediately by the Instance class definition, and followed by the use of the unordered_set container that uses it.
namespace ca
{
class Instance {...};
}
namespaces std {
template<> hash<Instance> { ... };
}
namespace ca {
class InstanceManager
{
// ... some other things.
private unordered_set<Instance>;
}
}
One drawback is that you can have funny name lookup interference when passing a std::hash<ca::Instance> to other functions. The reason is that the associated namespace (ca) of all the template arguments of std::hash can be used during name lookup (ADL). Such errors are a bit rare, but if they occur they can be hard to debug.
See this Q&A for more details.
Passing your hash to unordered_set
struct MyInstanceHash { ... };
using MyUnorderedSet = std:unordered_set<Instance, MyInstanceHash>;
Here, you simply pass your own hash function to the container and be done with it. The drawback is that you have to explicitly type your own container.
Using hash_append
Note, however, there is the N3980 Standard proposal is currently pending for review. This proposal features a much superior design that uses a universal hash function that takes an arbitrary byte stream to be hashed by its template parameter (the actual hashing algorithm)
template <class HashAlgorithm>
struct uhash
{
using result_type = typename HashAlgorithm::result_type;
template <class T>
result_type
operator()(T const& t) const noexcept
{
HashAlgorithm h;
using std::hash_append;
hash_append(h, t);
return static_cast<result_type>(h);
}
};
A user-defined class X then has to provide the proper hash_append through which it presents itself as a byte stream, ready to be hashed by the univeral hasher.
class X
{
std::tuple<short, unsigned char, unsigned char> date_;
std::vector<std::pair<int, int>> data_;
public:
// ...
friend bool operator==(X const& x, X const& y)
{
return std::tie(x.date_, x.data_) == std::tie(y.date_, y.data_);
}
// Hook into the system like this
template <class HashAlgorithm>
friend void hash_append(HashAlgorithm& h, X const& x) noexcept
{
using std::hash_append;
hash_append(h, x.date_);
hash_append(h, x.data_);
}
}
For more details, see the presentation by the author #HowardHinnant at CppCon14 (slides, video). Full source code by both the author and Bloomberg is available.
Do not specialise std::hash, instead write your own hash function object (see Edge_Hash below) and declare your unordered_set with two template arguments.
#include <unordered_set>
#include <functional>
namespace foo
{
// an edge is a link between two nodes
struct Edge
{
size_t src, dst;
};
// this is an example of symmetric hash (suitable for undirected graphs)
struct Edge_Hash
{
inline size_t operator() ( const Edge& e ) const
{
static std::hash<size_t> H;
return H(e.src) ^ H(e.dst);
}
};
// this keeps all edges in a set based on their hash value
struct Edge_Set
{
// I think this is what you're trying to do?
std::unordered_set<Edge,Edge_Hash> edges;
};
}
int main()
{
foo::Edge_Set e;
}
Related posts are, eg:
Inserting in unordered_set using custom hash function
Trouble creating custom hash function unordered_map
Thanks to everyone.
I have found the reason and solved the problem somehow: visual studio accepted the InstanceHash when I was defining instances_. Since I was changing the use of set to unordered_set, I forgot to specify InstanceHash when I tried to get the const_iterator, so this time the compiler tried to use the std::hash<> things and failed. But the compiler didn't locate the line using const_iterator, so I mistakenly thought it didn't accept InstanceHash when I was defining instances_.
I also tried to specialize the std::hash<> for class Instance. However, this specialization requires at least the declaration of class ca::Instance and some of its member functions to calculate the hash value. After this specialization, the definition of class ca::InstanceManage will use it.
I now generally put declarations and implementations of almost every classes and member functions together. So, the thing I need to do is probably to split the ca namespace scope to 2 parts and put the std{ template <> struct hash<ca::Instance>{...}} in the middle.

Using Concurrency::concurrent_queue together with std::unique_ptr

I want to use the Concurrency library of Visual Studio 2010 to pass actions between threads.
I have my class SimpleAction and pointers to it are stored in the Concurrency::concurrent_queue.
Using this definition, and 'consumption' logic it works:
typedef Concurrency::concurrent_queue<SimpleAction *> ActionQueue;
while (true)
{
SimpleAction *action = nullptr;
while (m_queue.try_pop(action))
{
action->process();
delete action;
}
Sleep(100);
}
However, when I change this to an std::unique_ptr, like this:
typedef Concurrency::concurrent_queue<std::unique_ptr<SimpleAction>> ActionQueue;
while (true)
{
std::unique_ptr<SimpleAction> action;
while (m_queue.try_pop(action))
{
action->process();
}
Sleep(100);
}
The compiler gives the following error message:
F:\DevStudio\Vs2010\VC\INCLUDE\concurrent_queue.h(366) : error C2248: 'std::unique_ptr<_Ty>::unique_ptr' : cannot access private member declared in class 'std::unique_ptr<_Ty>'
with
[
_Ty=`anonymous-namespace'::SimpleAction
]
F:\DevStudio\Vs2010\VC\INCLUDE\memory(2347) : see declaration of 'std::unique_ptr<_Ty>::unique_ptr'
with
[
_Ty=`anonymous-namespace'::SimpleAction
]
F:\DevStudio\Vs2010\VC\INCLUDE\concurrent_queue.h(365) : while compiling class template member function 'void Concurrency::concurrent_queue<_Ty>::_Copy_item(Concurrency::details::_Concurrent_queue_base_v4::_Page &,size_t,const void *)'
with
[
_Ty=std::unique_ptr<`anonymous-namespace'::SimpleAction>
]
test.cpp(138) : see reference to class template instantiation 'Concurrency::concurrent_queue<_Ty>' being compiled
with
[
_Ty=std::unique_ptr<`anonymous-namespace'::SimpleAction>
]
It seems the compiler does not like this construction in concurrent_queue:
/*override*/ virtual void _Copy_item( _Page& _Dst, size_t _Index, const void* _Src )
{
new( &_Get_ref(_Dst,_Index) ) _Ty(*static_cast<const _Ty*>(_Src));
}
Which seems logical (we don't want an std::unique_ptr to be copied (it must be moved instead).
Questions:
Is this a known problem/limitation/feature of the Concurrency/PPL library of Visual Studio 2010?
Is this problem solved in Visual Studio 2012?
Or am I doing something wrong?
thanks,
Patrick

Resources