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'
Related
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).
Can anyone help me with this errors. When i compile this simple program
#include<queue>
using namespace std;
template<typename Queue>
int qtest(Queue & queue,typename Queue::Type item)
{
return 0;
}
int main()
{
std::queue<int> q;
int t = qtest(q,3);
}
I get the errors like below
In function 'int main()':
error: no matching function for call to 'qtest(std::queue<int>&, int)'
note: candidate is:
note: template<class Queue> int qtest(Queue&, typename Queue::Type)
note: template argument deduction/substitution failed:
In substitution of 'template<class Queue> int qtest(Queue&, typename Queue::Type) [with
Queue = std::queue<int>]':
required from here
error: no type named 'Type' in 'class std::queue<int>'
warning: unused variable 't' [-Wunused-variable]
std::queue doesn't have a member type called Type. That's what the compiler is telling us. I'm guessing what you're looking for is std::queue<int>::value_type.
template<typename Queue>
int qtest(Queue & queue,typename Queue::value_type item)
{
return 0;
}
Reference: cppreference
I am trying to write a function that takes an Eigen::Vector<T, dim> as a parameter. However, the following example fails to compile:
#include <Eigen/Core>
template<class F, typename T, int dim>
void bar(F&& func, const Eigen::Vector<T, dim>& arg1) {
}
template<typename T, int dim>
void foo(const Eigen::Vector<T, dim>& a) {
return bar([] {}, a);
}
int main() {
Eigen::Vector<float, 3> v1{ 1.f,2.f,3.f };
foo(v1);
return 0;
}
This, under Visual Studio 2019, gives me the following error:
1>main.cpp(9,10): error C2672: 'bar': no matching overloaded function found
1>main.cpp(14): message : see reference to function template instantiation 'void foo<float,3>(const Eigen::Matrix<float,3,1,0,3,1> &)' being compiled
1>main.cpp(9,1): error C2784: 'void bar(F &&,const Eigen::Matrix<T,dim,1,|_Rows==&&?:&&_Rows!=?:,_Rows,1> &)': could not deduce template argument for 'const Eigen::Matrix<T,dim,1,|_Rows==&&?:&&_Rows!=?:,_Rows,1> &' from 'const Eigen::Matrix<float,3,1,0,3,1>'
1>main.cpp(4): message : see declaration of 'bar'
My questions:
What is this weird |_Rows==&&?:&&_Rows!=?: in the error message?
What can I do to make the above code compile?
The bar function should have T and dim availabe. I cannot just take const AnyType& arg1, because the actual implementation of bar depends on compile-time known values T and dim.
I have seen https://eigen.tuxfamily.org/dox/TopicFunctionTakingEigenTypes.html. I think I understand what they are saying, but I am not sure if it applies here. I am taking an actual Eigen::Vector as an argument, not an expression.
If there was an expression it would be fine for me, to have it materialized.
Nevertheless, if I try to follow their instruction and just use ArrayBase<Derived>, I lose the compile-time information about T and dim.
This indeed looks like an MSVC issue, it compiles fine with gcc >= 4.7, and clang >= 3.5: https://godbolt.org/z/kqoHyO
One possible workaround would be to explicitly write out what Eigen::Vector expands to:
template<class F, typename T, int dim>
void bar(F&& func, const Eigen::Matrix<T, dim, 1, 0, dim, 1>& arg1) {
}
https://godbolt.org/z/vlvSDP
The weird |_Rows==&&?:&&_Rows!=?: looks like MSVC mangled the default value of the Options template parameter:
AutoAlign |
( (_Rows==1 && _Cols!=1) ? Eigen::RowMajor
: (_Cols==1 && _Rows!=1) ? Eigen::ColMajor
: EIGEN_DEFAULT_MATRIX_STORAGE_ORDER_OPTION ),
If you want to get to the bottom of this, you should file a bug-report to the MSVC maintainers, maybe using a simplified example like this: https://godbolt.org/z/U_0Sh7 (probably it's possible to reduce this even more).
I am trying to make a Variadic Delegate structure while trying to grasp templates and variadic template arguments. I came up with the following:
template <typename T, typename R, typename... Parameters>
class Delegate
{
private:
T& object;
R (T::*method)(Parameters...);
public:
Delegate(T& object, R(T::*method)(Parameters...))
: object(object), method(method)
{}
R Call(Parameters...)
{
return (object.*method)(Parameters...);
}
};
and my main function looks like this:
class A
{
public:
int F(int a)
{
return a * x;
}
int x;
};
int main()
{
A a;
a.x = 5;
Delegate<A, int, int> d(a, &A::F);
d.Call(8);
return 0;
}
But that gives me the following errors:
error C2144: syntax error : 'int' should be preceded by ')'
while compiling class template member function 'int Swift::Utility::Delegate<A,int,int>::Call(int)'
error C2198: 'int (__thiscall A::* )(int)' : too few arguments for call
error C2059: syntax error : ')'
I tried some different ways on calling the member functions but I can't get it to work...
Also if you can show me a different alternative that provides the same basic functionality I would also be happy!
You're not providing actual arguments, only their types:
R Call(Parameters... params)
{
return (object.*method)(params...);
}
is probably what you were looking for (or close to it).
Given the following class and function templates:
template <typename WrappedType, ParameterType ParamType, bool IsOutputParameter>
class WrappedParameter; // Definition left out for brevity
template <typename T>
struct ParameterUnwrapper
{
static T UnwrapParameter(const T& in_param)
{
return in_param;
}
};
template <typename T, ParameterType ParamType, bool IsOutputParameter>
struct ParameterUnwrapper<WrappedParameter<T, ParamType, IsOutputParameter>>
{
static T UnwrapParameter(const WrappedParameter<T, ParamType, IsOutputParameter>& in_param)
{
return in_param.GetWrapped();
}
};
template <typename T>
T UnwrapParameter(T in_param)
{
return Impl::ParameterUnwrapper<T>::UnwrapParameter(in_param);
}
template <typename T>
Impl::WrappedParameter<T, Impl::POINTER_PARAMETER, true> WrapOutputPointerParameter(T in_param)
{
return Impl::WrappedParameter<T, Impl::POINTER_PARAMETER, true>(in_param);
}
template <typename MemFunc, typename ...Args>
HRESULT ExecuteAndLog(
MemFunc in_memberFunction,
const std::string& in_methodName,
Args... args) //-> decltype((m_wrapped->*in_memberFunction)(UnwrapParameter(args)...))
{
return ExecuteFunctorAndLog(
[&]() { return (m_wrapped->*in_memberFunction)(UnwrapParameter(args)...); },
in_methodName,
args...);
}
The following call: (The ExecuteAndLog)
HRESULT STDMETHODCALLTYPE AccessorWrapper::AddRefAccessor(
HACCESSOR hAccessor,
DBREFCOUNT *pcRefCount)
{
return ExecuteAndLog(
&IAccessor::AddRefAccessor,
"AddRefAccessor",
hAccessor,
WrapOutputPointerParameter(pcRefCount));
}
Gives me errors:
error C2664: 'HRESULT (HACCESSOR,DBREFCOUNT *)' : cannot convert argument 2 from 'Impl::WrappedParameter<DBREFCOUNT *,POINTER_PARAMETER,true>' to 'DBREFCOUNT *'
No user-defined-conversion operator available that can perform this conversion, or the operator cannot be called
see reference to function template instantiation 'ExecuteAndLog<HRESULT(__stdcall IAccessor::* )(HACCESSOR,DBREFCOUNT *),HACCESSOR, Impl::WrappedParameter<DBREFCOUNT *,POINTER_PARAMETER,true>>(MemFunc,const std::string &,HACCESSOR,Impl::WrappedParameter<DBREFCOUNT *,POINTER_PARAMETER,true>)' being compiled
with
[
MemFunc=HRESULT (__stdcall IAccessor::* )(HACCESSOR,DBREFCOUNT *)
]
see reference to function template instantiation 'ExecuteAndLog<HRESULT(__stdcall IAccessor::* )(HACCESSOR,DBREFCOUNT *),HACCESSOR,Impl::WrappedParameter<DBREFCOUNT *,POINTER_PARAMETER,true>>(MemFunc,const std::string &,HACCESSOR,Impl::WrappedParameter<DBREFCOUNT *,POINTER_PARAMETER,true>)' being compiled
with
[
MemFunc=HRESULT (__stdcall IAccessor::* )(HACCESSOR,DBREFCOUNT *)
]
I think I've messed up the partial specialization of ParameterUnwrapper (or my approach is just wrong). Any advice?
More information:
Impl is a nested namespace (alongside the namespace all the provided templates except ExecuteAndLog are in)
m_wrapped is of type IAccessor* (the COM interface) in this case.
enum ParameterType
{
POINTER_PARAMETER,
ARRAY_PARAMETER
};
UPDATE:
Here's a self contained example: http://codepad.org/lwTzVImb
The error I get in VS2013 for this one is:
error C2664: 'int (int,int **,size_t *)' : cannot convert argument 2 from 'WrappedParameter<int **,ARRAY_PARAMETER,true>' to 'int **'
No user-defined-conversion operator available that can perform this conversion, or the operator cannot be called
see reference to function template instantiation 'int ExecuteAndLog<int(__thiscall A::* )(int,int **,size_t *),int,WrappedParameter<int **,ARRAY_PARAMETER,true>,size_t*>(MemFunc,const std::string &,int,WrappedParameter<int **,ARRAY_PARAMETER,true>,size_t *)' being compiled
with
[
MemFunc=int (__thiscall A::* )(int,int **,size_t *)
]
I figured it out!
The issue was the return type of UnwrapParameter. Once I changed the declaration of it to
template <typename T>
auto UnwrapParameter(T in_param) -> decltype(Impl::ParameterUnwrapper<T>::UnwrapParameter(in_param))
It compiled. Shame the compiler didn't complain about the definition of that function, rather than trusting its declared return value.
I have some other problems right now but at least I've made progress.