Error during template substitution reported by compiler - c++11

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.

Related

What's the right way to call static_assert(false)?

I’m trying to use static_assert to force something to fail. If you try to instantiate a specific templated function in a specific way I want to generate a complier error. I could make it work, but it was really ugly. Is there an easier way to do this?
This was my first attempt. This did not work at all. It always generates an error, even if no one tries to use this function.
template< class T >
void marshal(std::string name, T *value)
{
static_assert(false, "You cannot marshal a pointer.");
}
Here’s my second attempt. It actually works. If you don’t call this, you get no error. If you do call this, you get a very readable error message that points to this line and points to the code that tried to instantiate it.
template< class T >
void marshal(std::string name, T *value)
{
static_assert(std::is_pod<T>::value && !std::is_pod<T>::value, "You cannot marshal a pointer.");
}
The problem is that this code is ugly at best. It looks like a hack. I’m afraid the next time I change the optimization level, upgrade my compiler, sneeze, etc, the compiler will realize that this second case is the same as the first, and they will both stop working.
Is there a better way to do what I’m trying to do?
Here’s some context. I want to have several different versions of marshal() which work for different input types. I want one version that uses a template as the default case. I want another one that specifically disallows any pointers except char *.
void marshal(std::string name, std::string)
{
std::cout<<name<<" is a std::string type."<<std::endl;
}
void marshal(std::string name, char *string)
{
marshal(name, std::string(string));
}
void marshal(std::string name, char const *string)
{
marshal(name, std::string(string));
}
template< class T >
void marshal(std::string name, T value)
{
typedef typename std::enable_if<std::is_pod<T>::value>::type OnlyAllowPOD;
std::cout<<name<<" is a POD type."<<std::endl;
}
template< class T >
void marshal(std::string name, T *value)
{
static_assert(false, "You cannot marshal a pointer.");
}
int main (int argc, char **argv)
{
marshal(“should be pod”, argc);
marshal(“should fail to compile”, argv);
marshal(“should fail to compile”, &argc);
marshal(“should be std::string”, argv[0]);
}
There is no way to do this. You might be able to make it work on your compiler, but the resulting program is ill formed no diagnostic required.
Use =delete.
template< class T >
void marshal(std::string name, T *value) = delete;
What you are trying to do is doomed to be ill-formed (even your workaround can fail) according to [temp.res]/8 (emphasis mine):
Knowing which names are type names allows the syntax of every template
to be checked. The program is ill-formed, no diagnostic required, if:
- no valid specialization can be generated for a template or a substatement of a constexpr if statement within a template and the
template is not instantiated, or (...)
Relying on a contradiction is not the best indeed, but there's a simpler way:
template <class...>
struct False : std::bool_constant<false> { };
template <class T>
void bang() {
static_assert(False<T>{}, "bang!");
}
Why does this not fall under the "no valid specialization" case?
Well, because you can actually make a valid specialization, with that second half of the code:
template <>
struct False<int> : std::bool_constant<true> { };
int main() {
bang<int>(); // No "bang"!
}
Of course, no one is actually going to specialize False to break your assertions in real code, but it is possible :)
I don't understand why you have template< class T > void marshal(std::string name, T *value) in the first place. This should just be a static_assert in the primary template.
That is, you should change the definition of your primary template to
template< class T >
void marshal(std::string name, T value)
{
static_assert(std::is_pod<T>::value);
static_assert(!std::is_pointer<T>::value);
std::cout<<name<<" is a POD type."<<std::endl;
}

C++/CLI Compilation error with generic delegate

I'm currently doing some work with C++/CLI, and am encountering a strange compilation error with the following code:
private ref class LinqHelper abstract sealed
{
public:
generic<typename T, typename U> static Func<T, U>^ Cast()
{
return gcnew Func<T, U>(&LinqHelper::Cast);
}
private:
generic<typename T, typename U> static U Cast(T val)
{
return safe_cast<U>(val);
}
};
error C3352: 'Cast' : the specified function does not match the delegate type 'U (T)'
To be more specific, the problematic line of code is:
return gcnew Func<T, U>(&LinqHelper::Cast);
I find myself at a loss to explain this error. The Cast static member function that I am passing to the Func delegate constructor has the required signature, i.e. U Cast(T val).
Could anyone help shed some light on this for me please?
If it is of any help: i am working with VS 2015 and the C++/CLI project is referencing the .NET framework v4.5.2.
Thank you
The compiler is not happy about having to infer the type arguments for the Cast method. Lousy error message, not uncommon in C++/CLI. Fix:
return gcnew Func<T, U>(&LinqHelper::Cast<T, U>);

Why can a std::vector of uncopiable objects not be initialized with an initializer_list?

Why does this not compile? (it needs a copy-constructor for std::unique_ptr<>)
std::vector<std::unique_ptr<int>> vec{std:unique_ptr<int>(new int)};
The created pointer is an r-value so why can it not be moved into the vector?
Is there an equally short way of initializing the vector that works?
The simple problem is that std::unique_ptr's copy-ctor is deleted, but the construct of std:: that is found invokes ::new which triggers a call to that deleted copy-ctor.
libc++/clang++-3.5
/usr/include/c++/v1/memory:1645:31: error: call to implicitly-deleted copy constructor of 'std::__1::unique_ptr >'
template <class _Up, class... _Args>
_LIBCPP_INLINE_VISIBILITY
void
construct(_Up* __p, _Args&&... __args)
{
::new((void*)__p) _Up(_VSTD::forward<_Args>(__args)...);
}
libstdc++/g++-4.9
/usr/include/c++/4.9/bits/stl_construct.h:75:7: error: use of deleted function
‘std::unique_ptr<_Tp, _Dp>::unique_ptr(const std::unique_ptr<_Tp, _Dp>&)
[with _Tp = int; _Dp = std::default_delete<int>]’
{ ::new(static_cast<void*>(__p)) _T1(std::forward<_Args>(__args)...); }
It somewhat tempting to try and formulate a custom overload of std::allocator as use it for the container's allocator type.
For those who cannot resist that temptation (like me)
To make a custom allocator at least used by the compiler it at least needs this minimum population.
template<typename T>
struct allocator : public std::allocator<T> {
using Base = std::allocator<T>;
using Base::Base;
template<typename U>
struct rebind {typedef allocator<U> other;};
template<typename Up, typename... Args>
void construct(Up* p, Args&&... args);
};
That is hardly complete yet (let alone would I have construct properly re-implemented yet), but at least it summons the error up from the abysses of the lib into the daylight a custom source file.

Parameter pack expansion fails

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;
}

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