I try to compile a personal project on Visual Studio 2019 (using MSVC 19.28 compiler) and I came accross a compilation error in the std::visit which I don't understand:
<source>(131): error C2653: '`global namespace'': is not a class or namespace name
C:/data/msvc/14.28.29914/include\type_traits(1493): note: see reference to function template instantiation 'auto CommandLineOptionsParser<CmdLineOpts>::register_callback::<lambda_1>::()::<lambda_1>::operator ()<const _First&>(_T1) const' being compiled
with
[
_First=bool CmdLineOpts::* ,
_T1=bool CmdLineOpts::* const &
]
C:/data/msvc/14.28.29914/include\variant(1654): note: see reference to alias template instantiation 'std::_Variant_visit_result_t<CommandLineOptionsParser<CmdLineOpts>::register_callback::<lambda_1>::()::<lambda_1>,const std::variant<bool CmdLineOpts::* >&>' being compiled
<source>(120): note: while compiling class template member function 'void CommandLineOptionsParser<CmdLineOpts>::register_callback(const CommandLineOption &,std::variant<bool CmdLineOpts::* >)'
<source>(83): note: see reference to function template instantiation 'void CommandLineOptionsParser<CmdLineOpts>::register_callback(const CommandLineOption &,std::variant<bool CmdLineOpts::* >)' being compiled
<source>(142): note: see reference to class template instantiation 'CommandLineOptionsParser<CmdLineOpts>' being compiled
<source>(123): error C2672: 'visit': no matching overloaded function found
<source>(131): error C2893: Failed to specialize function template 'unknown-type std::visit(_Callable &&,_Variants &&...)'
C:/data/msvc/14.28.29914/include\variant(1654): note: see declaration of 'std::visit'
<source>(131): note: With the following template arguments:
<source>(131): note: '_Callable=CommandLineOptionsParser<CmdLineOpts>::register_callback::<lambda_1>::()::<lambda_1>'
<source>(131): note: '_Variants={const std::variant<bool CmdLineOpts::* > &}'
<source>(131): note: '<unnamed-symbol>=void'
Compiler returned: 2
This code compiles fine with gcc.
I tested the code snippet from cppreference on std::visit and it compiles with MSVC, so I am not so sure what the issue here.
I simplified the code and reproduced the issue on godbolt
Here's the code
#include <algorithm>
#include <functional>
#include <iostream>
#include <map>
#include <memory>
#include <sstream>
#include <string>
#include <set>
#include <string_view>
#include <variant>
#include <type_traits>
using InvalidArgumentException = std::invalid_argument;
using CommandLineOption = std::string;
template <class Opts>
class CommandLineOptionsParser : Opts {
public:
using OptionType = std::variant<bool Opts::*>;
using CommandLineOptionWithValue = std::pair<CommandLineOption, OptionType>;
Opts parse(const char* argStr) {
// First register the callbacks
bool Opts::* pBool = &Opts::help;
register_callback("help", pBool);
for (auto& cbk : _callbacks) {
cbk.second(0, argStr);
}
return static_cast<Opts>(*this);
}
private:
using callback_t = std::function<void(int, const char *)>;
std::map<CommandLineOption, callback_t> _callbacks;
void register_callback(const CommandLineOption& commandLineOption, OptionType prop) {
_callbacks[commandLineOption] = [this, &commandLineOption, prop](int idx, const char * argv) {
if (std::string(argv) == commandLineOption) {
std::visit([](auto&& a) {
using T = std::decay_t<decltype(a)>;
if constexpr (std::is_same_v<T, bool Opts::*>) {
std::cout << "bool" << std::endl;
}
},
prop);
}
};
};
};
struct CmdLineOpts {
bool help{};
};
int main(int argc, const char* argv[])
{
CommandLineOptionsParser<CmdLineOpts> p;
CmdLineOpts cmdLineOptions = p.parse("opt1");
}
It seems MSVC is having difficulty synthesizing a lambda with a pointer-to-member argument in a template context.
I tried to simplify it to a MCVE, hopefully it captures the essence of the issue:
template<class T>
bool test(int T::* t) {
return [](int T::* x) {
return true;
}(t);
}
struct A {
int a;
};
int main() {
return test<A>(&A::a);
}
It fails to compile in MSVC C++20 mode (but not C++17) with a similar nonsensical error (link):
<source>(5): error C2653: '`global namespace'': is not a class or namespace name
<source>(13): note: see reference to function template instantiation 'bool test<A>(int A::* )' being compiled
<source>(5): error C2664: 'bool test::<lambda_1>::operator ()(A *) const': cannot convert argument 1 from 'int A::* ' to 'A *'
<source>(5): note: There is no context in which this conversion is possible
<source>(5): note: see declaration of 'test::<lambda_1>::operator ()'
I would suggest to report this to the vendor.
As a potential workaround can try extracting the lambda into a functor class with a templated operator(), it seems to compile (example).
Related
While creating a subclass of a template class I noticed I got an error on an overloaded function.
This compiler error was correct since one of the overloads was using a copy and the type was not copyable.
However, I was not using that function (correct overload or not). So I was surprised to get this error
After searching around a bit and reproducing in godbolt the culprit seemed to be __declspec(dllexport).
Reproduction in godbolt
Removing the declspec seems to result in the correct compilation.
Code in godbolt:
#include <memory>
#include <vector>
using namespace std;
template<class V>
struct Foo{
void update(const V& v);
void update(V&& v);
std::vector<V> values;
};
template<class V>
void Foo<V>::update(const V& v)
{
values[0] = v;
}
template<class V>
void Foo<V>::update(V&& v)
{
values[0] = std::move(v);
}
struct __declspec(dllexport) Bar : public Foo<std::unique_ptr<int>>
{
};
int main()
{
Bar f;
auto i = std::make_unique<int>(5);
//f.update(i);
//f.update(std::move(i));
}
My questions are mostly, how is declspec causing this behavior?
And, is there anything that can be done about this in the template class or derived class?
Error log:
(19): error C2280:
'std::unique_ptr>
&std::unique_ptr>::operator =(const
std::unique_ptr> &)': attempting to
reference a deleted function with [
_Ty=int ] C:/data/msvc/14.16.27023.1/include\memory(2338): note: see declaration of
'std::unique_ptr>::operator =' with
[
_Ty=int ] C:/data/msvc/14.16.27023.1/include\memory(2338): note: 'std::unique_ptr>
&std::unique_ptr>::operator =(const
std::unique_ptr> &)': function was
explicitly deleted with [
_Ty=int ] (18): note: while compiling class template member function 'void
Foo>>::update(const V &)'
with [
_Ty=int,
V=std::unique_ptr> ] (29): note: see reference to class template instantiation
'Foo>>' being compiled
with [
_Ty=int ]
I am trying to make a template function that is will only get used for invocables that match a certain i pattern (in the example, accept int and return int). I tried this but it doesn't compile. Can anyone explain to me why?
#include <iostream>
#include <type_traits>
int foo(int) {return 0;}
int foo(char*) {return 0;}
template<class T>
std::enable_if_t<std::is_invocable_r_v<int, T, int>>
add(T t) {}
int main()
{
add(foo);
}
The error I get (VS2017):
main.cpp(13): error C2672: 'add': no matching overloaded function found
main.cpp(13): error C2783: 'enable_if<_Test,_Ty>::type add(T)': could not deduce template argument for 'T'
with
[
_Ty=void
]
main.cpp(9): note: see declaration of 'add'
I want to add some information about parameters in my program (type and convertation function). Name of parameters is const. I wrote some code for it, but it not compile in MSVC 2017 (on GCC or Clang is OK)
#include <iostream>
#include <string>
namespace params
{
constexpr wchar_t CLIENT_LOGIN[] = L"ClientLogin";
template<const wchar_t * ParamName>
struct convert_traits
{
};
template<>
struct convert_traits<CLIENT_LOGIN>
{
using ConvertType = unsigned long long;
static ConvertType convert(const std::wstring &str)
{
return std::stoull(str);
}
};
}
int main() {
std::cout << params::convert_traits<params::CLIENT_LOGIN>::convert(L"123.0") << std::endl;
return 0;
}
I receive errors:
main.cpp(15): error C2971: 'params::convert_traits': template parameter 'ParamName': 'params::CLIENT_LOGIN': a variable with non-static storage duration cannot be used as a non-type argument
main.cpp(10): note: see declaration of 'params::convert_traits'
main.cpp(6): note: see declaration of 'params::CLIENT_LOGIN'
main.cpp(26): error C2971: 'params::convert_traits': template parameter 'ParamName': 'params::CLIENT_LOGIN': a variable with non-static storage duration cannot be used as a non-type argument
main.cpp(10): note: see declaration of 'params::convert_traits'
main.cpp(6): note: see declaration of 'params::CLIENT_LOGIN'
and can't found a fix for MSVC.
Solved with
extern const wchar_t CLIENT_LOGIN[] = L"ClientLogin";
but not work if define it in header.
I recently spent quite some time understanding the error message when calling func() in this piece of code:
int main()
{
vector< vector<double> > v;
double sum = 0;
for_each( v.begin(), v.end(),
bind2nd( ptr_fun(func), &sum ) );
return 0;
}
when func() was declared like so, the code compiled fine:
void func( vector<double> v, double *sum )
{
}
when I used this declaration (for efficiency), I got a compiler error:
void func( const vector<double> &v, double *sum )
{
}
The error I expected to see was something like a reference-to-reference error, because of the definition of operator() of binder2nd,
result_type operator()(const argument_type& _Left) const
Instead, to my surprise, the error the Visual C++ (VS2012) compiler gave me was:
error C2535: 'void std::binder2nd<_Fn2>::operator ()(const
std::vector<_Ty> &) const' : member function already defined or
declared
which I cannot decipher.
Can you explain under which mechanism the operator() is already
defined?
The full error I got was:
error C2535: 'void std::binder2nd<_Fn2>::operator ()(const std::vector<_Ty> &) const' : member function already defined or declared
with
[
_Fn2=std::pointer_to_binary_function<const std::vector<double> &,double *,void,void (__cdecl *)(const std::vector<double> &,double *)>,
_Ty=double
]
c:\vc\include\xfunctional(319) : see declaration of 'std::binder2nd<_Fn2>::operator ()'
with
[
_Fn2=std::pointer_to_binary_function<const std::vector<double> &,double *,void,void (__cdecl *)(const std::vector<double> &,double *)>
]
c:\consoleapplication1.cpp(31) : see reference to class template instantiation 'std::binder2nd<_Fn2>' being compiled
with
[
_Fn2=std::pointer_to_binary_function<const std::vector<double> &,double *,void,void (__cdecl *)(const std::vector<double> &,double *)>
]
Build FAILED.
This behavior is well-defined (every correct C++ compiler will fail to compile your code).
From the standard (N3376) section D.9.3 on class template binder2nd, these two defintions of operator() exist:
typename Fn::result_type
operator()(const typename Fn::first_argument_type& x) const;
typename Fn::result_type
operator()(typename Fn::first_argument_type& x) const;
If first_argument_type is already a const T&, then they will be conflicting.
This isn't an answer, but I just want to record the modern C++11 solution, where all the small bind helpers are deprecated in favour of the universal std::bind:
#include <functional>
#include <vector>
#include <algorithm>
void func(std::vector<double> const & v, double * sum) { /* ... */ }
int main()
{
std::vector<std::vector<double>> v;
double sum = 0;
std::for_each(v.begin(), v.end(), std::bind(func, std::placeholders::_1, &sum));
}
The variadic templates of C++11, as well as a more comprehensive collection of type-modifying traits, give std::bind much stronger deduction abilities than the previous components in <functional>.
I have a bunch of templated code that compiles fine under g++, but now when I try to build under windows with Visual C++ 2010 I get a bunch of errors.
I have a collection of template functions for getting and setting values in C++ objects from Lua code. For example, I have this template:
// Class Return type Getter function
template <typename T, typename U, U (T::*Getter)() const>
int luaU_get(lua_State* L)
{
T* obj = luaW_check<T>(L, 1); // Gets userdata from stack and checks if it's of type T
luaU_push(L, (obj->*Getter)()); // Runs the getter function specified in the template, and pushes the
return 1;
}
(The complete file can be found here)
Which is instantiated here:
static luaL_reg TextArea_MT[] =
{
// Class Return type Getter function
{ "GetCharacterSize", luaU_get<TextArea, unsigned int, &TextArea::GetCharacterSize> },
{ NULL, NULL }
};
The signature for that getter is as follows:
unsigned int GetCharacterSize() const;
I'm getting a bunch of errors like this:
2>C:\Users\Alex\Documents\Visual Studio 2010\Projects\game\dev\src\game\lua\LuaTextArea.cpp(103): error C2440: 'specialization' : cannot convert from 'unsigned int (__thiscall ag::ui::TextArea::* )(void) const' to 'unsigned int *(__thiscall ag::ui::TextArea::* const )(void) const'
2> Types pointed to are unrelated; conversion requires reinterpret_cast, C-style cast or function-style cast
2>C:\Users\Alex\Documents\Visual Studio 2010\Projects\game\dev\src\game\lua\LuaTextArea.cpp(103): error C2973: 'luaU_get' : invalid template argument 'unsigned int (__thiscall ag::ui::TextArea::* )(void) const'
2> C:\Users\Alex\Documents\Visual Studio 2010\Projects\game\dev\src\extern\LuaWrapper\LuaWrapperUtil.hpp(147) : see declaration of 'luaU_get'
2>C:\Users\Alex\Documents\Visual Studio 2010\Projects\game\dev\src\game\lua\LuaTextArea.cpp(103): error C2440: 'specialization' : cannot convert from 'unsigned int (__thiscall ag::ui::TextArea::* )(void) const' to 'unsigned int *ag::ui::TextArea::* const '
2> There is no context in which this conversion is possible
2>C:\Users\Alex\Documents\Visual Studio 2010\Projects\game\dev\src\game\lua\LuaTextArea.cpp(103): error C2973: 'luaU_get' : invalid template argument 'unsigned int (__thiscall ag::ui::TextArea::* )(void) const'
2> C:\Users\Alex\Documents\Visual Studio 2010\Projects\game\dev\src\extern\LuaWrapper\LuaWrapperUtil.hpp(131) : see declaration of 'luaU_get'
2>C:\Users\Alex\Documents\Visual Studio 2010\Projects\game\dev\src\game\lua\LuaTextArea.cpp(103): error C2440: 'specialization' : cannot convert from 'unsigned int (__thiscall ag::ui::TextArea::* )(void) const' to 'unsigned int ag::ui::TextArea::* const '
2> There is no context in which this conversion is possible
2>C:\Users\Alex\Documents\Visual Studio 2010\Projects\game\dev\src\game\lua\LuaTextArea.cpp(103): error C2973: 'luaU_get' : invalid template argument 'unsigned int (__thiscall ag::ui::TextArea::* )(void) const'
2> C:\Users\Alex\Documents\Visual Studio 2010\Projects\game\dev\src\extern\LuaWrapper\LuaWrapperUtil.hpp(123) : see declaration of 'luaU_get'
2>C:\Users\Alex\Documents\Visual Studio 2010\Projects\game\dev\src\game\lua\LuaTextArea.cpp(103): error C2440: 'initializing' : cannot convert from 'overloaded-function' to 'lua_CFunction'
2> None of the functions with this name in scope match the target type
This is a compiler bug in VC++. The following code is valid:
#include <iostream>
struct TextArea
{
unsigned GetCharacterSize() const { return 0; }
};
template<typename T, typename U, U (T::*)() const>
int foo()
{
return 1;
}
template<typename T, typename U, U* (T::*)() const>
int foo()
{
return 2;
}
int main()
{
std::cout << foo<TextArea, unsigned, &TextArea::GetCharacterSize>() << '\n';
}
And compiles with GCC 4.3.4, GCC 4.5.1, and Comeau 4.3.10.1 Beta2 (no link), but yields the following error with VC++ 2010 SP1:
error C2668: 'foo' : ambiguous call to overloaded function
EDIT: As for a workaround, it's ugly, but the only thing I can think of offhand is to use an extra layer of indirection so that there is no overloading involved:
#include <iostream>
struct WithPointer
{
unsigned* GetCharacterSize() const { return nullptr; }
};
struct WithoutPointer
{
unsigned GetCharacterSize() const { return 0u; }
};
template<bool UsePointerImplB>
struct kludge
{
template<typename T, typename U, U (T::*Getter)() const>
static int foo() { return 1; }
};
template<>
struct kludge<true>
{
template<typename T, typename U, U* (T::*Getter)() const>
static int foo() { return 2; }
};
int main()
{
std::cout
<< kludge<false>::foo<WithoutPointer, unsigned, &WithoutPointer::GetCharacterSize>() << '\n'
<< kludge<true>::foo<WithPointer, unsigned, &WithPointer::GetCharacterSize>() << '\n';
}
Effectively this is no different than just giving each overload a different name...
If you can force user to pick the actual return type of the function, the following works. Maybe, it'll be useful to you:
#include <iostream>
struct FooBar
{
int Foo( void ) const
{
std::cout << "FooBar::Foo()" << std::endl;
return ( 0 );
}
int * Bar( void ) const
{
std::cout << "FooBar::Bar()" << std::endl;
return ( 0 );
}
};
template< typename P00, typename P01, P01(P00::*p02)( void ) const >
void Call()
{
P00 lT;
( lT.*p02 )();
}
int main( void )
{
Call< FooBar, int, &FooBar::Foo > ();
Call< FooBar, int*, &FooBar::Bar > ();
return( 0 );
}
Program output:
FooBar::Foo()
FooBar::Bar()