Removing unnecessary template argument, but doesn't compile anymore - c++

I have two different approaches to a templated function using auto and decltype but one of them does not compile, yielding two error:
Where is the main difference between the following versions of the code:
This compiles
template<typename MemoryMapper, typename EngineParts>
class EngineBase {
const MemoryMapper memoryMapper;
public:
const EngineParts engineParts;
EngineBase();
virtual ~EngineBase();
template<typename Mapper, typename MemoryAccessor>
void getMemoryManager(void);
template<MemoryMapper,typename MemoryAccessor>
auto getMemoryManager(void)->decltype(memoryMapper.getMemoryManager<MemoryAccessor>())
{
return memoryMapper.getMemoryManager<MemoryAccessor>();
}
};
While this does not
template<typename MemoryMapper, typename EngineParts>
class EngineBase {
const MemoryMapper memoryMapper;
public:
const EngineParts engineParts;
EngineBase();
virtual ~EngineBase();
template<typename MemoryAccessor>
auto getMemoryManager(void)->decltype(memoryMapper.getMemoryManager<MemoryAccessor>())
{
return memoryMapper.getMemoryManager<MemoryAccessor>();
}
};
The error output is as follows:
g++ -O0 -g3 -Wall -c -fmessage-length=0 -std=c++0x -o EngineBase.o "..\\EngineBase.cpp"
In file included from ..\EngineBase.cpp:7:0:
..\EngineBase.h:22:84: error: expected primary-expression before '>' token
auto getMemoryManager(void)->decltype(memoryMapper.getMemoryManager<MemoryAccessor>())
^
..\EngineBase.h:22:86: error: expected primary-expression before ')' token
auto getMemoryManager(void)->decltype(memoryMapper.getMemoryManager<MemoryAccessor>())
^
14:50:52 Build Finished (took 2s.587ms)
Since I don't want to specifically write the first template argument on every use and it would create the impression that there are more functions defined than realistically are, how can I get the second version to work without introducing another template argument? Function parameters would be ok, though.

template<typename MemoryAccessor>
auto getMemoryManager(void)->decltype(memoryMapper.template getMemoryManager<MemoryAccessor>())
// ~~~~~~~^
{
return memoryMapper.template getMemoryManager<MemoryAccessor>();
// ~~~~~~~^
}

Related

class template fails to compile when named lambda is used as template class argument or constructor argument

I'm currently experimenting with class template programming and I came across this weird behavior that I cant understand when passing a named lambda as its argument. Could somebody explain why (1) & (2) below does not work?
template<typename Predicate>
class Test{
public:
Test(Predicate p) : _pred(p) {}
private:
Predicate _pred;
};
int main(){
auto isEven = [](const auto& x){ return x%2 == 0; };
// Working cases
Test([](const auto& x){ return x%2 == 0; });
Test{isEven};
auto testObject = Test(isEven);
// Compilation Error cases
Test(isEven); // (1) Why??? Most vexing parse? not assigned to a variable? I cant understand why this fails to compile.
Test<decltype(isEven)>(isEven); // (2) Basically same as (1) but with a workaround. I'm using c++17 features, so I expect automatic class parameter type deduction via its arguments
return 0;
};
Compiler Error message: Same for (1) & (2)
cpp/test_zone/main.cpp: In function ‘int main()’:
cpp/test_zone/main.cpp:672:16: error: class template argument deduction failed:
Test(isEven);
^
cpp/test_zone/main.cpp:672:16: error: no matching function for call to ‘Test()’
cpp/test_zone/main.cpp:623:5: note: candidate: template<class Predicate> Test(Predicate)-> Test<Predicate>
Test(Predicate p): _p(p){
^~~~
cpp/test_zone/main.cpp:623:5: note: template argument deduction/substitution failed:
cpp/test_zone/main.cpp:672:16: note: candidate expects 1 argument, 0 provided
Test(isEven);
^
Please forgive my formatting, and compile error message snippet as it does not match exact lines. I'm using g++ 7.4.0, and compiling with c++17 features.
In C++, you can declare a variable as
int(i);
which is the same as
int i;
In your case, the lines
Test(isEven);
Test<decltype(isEven)>(isEven);
are compiled as though you are declaring the variable isEven. I am surprised that the error message from your compiler is so different than what I hoped to see.
You can reproduce the problem with a simple class too.
class Test{
public:
Test(int i) : _i(i) {}
private:
int _i;
};
int main(){
int i = 10;
Test(i);
return 0;
};
Error from my compiler, g++ 7.4.0:
$ g++ -std=c++17 -Wall socc.cc -o socc
socc.cc: In function ‘int main()’:
socc.cc:15:11: error: conflicting declaration ‘Test i’
Test(i);
^
socc.cc:10:9: note: previous declaration as ‘int i’
int i = 10;
As you said, this is a most vexing parse issue; Test(isEven); is trying to redefine a variable with name isEven, and same for Test<decltype(isEven)>(isEven);.
As you showed, you can use {} instead of (), this is the best solution since C++11; or you can add additional parentheses (to make it a function-style cast).
(Test(isEven));
(Test<decltype(isEven)>(isEven));
LIVE

Parse error in template argument list, expected identifier

I'm trying to compile the EnTT library (version 2.7.3 for cpp14) using MinGW GCC-6.3.0 in Eclipse Oxygen. When compiling, I get these errors:
Info: Internal Builder is used for build
g++ -std=c++1y -D__GXX_EXPERIMENTAL_CXX0X__ -O0 -g3 -Wall -c -fmessage-length=0 -std=c++14 -o "source\\main.o" "..\\source\\main.cpp"
In file included from c:\mingw\include\entt\entt.hpp:10:0,
from ..\source\includes.hpp:23,
from ..\source\main.cpp:1:
c:\mingw\include\entt\entity/helper.hpp: In function 'void entt::connect(entt::Sink<void(entt::Registry<Entity>&, Entity)>)':
c:\mingw\include\entt\entity/helper.hpp:56:19: error: parse error in template argument list
sink.template connect<dependency<Entity, Dependency...>>();
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
c:\mingw\include\entt\entity/helper.hpp:56:19: error: expected identifier
c:\mingw\include\entt\entity/helper.hpp: In function 'void entt::disconnect(entt::Sink<void(entt::Registry<Entity>&, Entity)>)':
c:\mingw\include\entt\entity/helper.hpp:79:19: error: parse error in template argument list
sink.template disconnect<dependency<Entity, Dependency...>>();
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
c:\mingw\include\entt\entity/helper.hpp:79:19: error: expected identifier
Here are the truculent functions in question:
template<typename Entity, typename... Component>
void dependency(Registry<Entity> &registry, const Entity entity) {
using accumulator_type = int[];
accumulator_type accumulator = { ((registry.template has<Component>(entity) ? void() : (registry.template assign<Component>(entity), void())), 0)... };
(void)accumulator;
}
template<typename... Dependency, typename Entity>
inline void connect(Sink<void(Registry<Entity> &, const Entity)> sink) {
sink.template connect<dependency<Entity, Dependency...>>();
}
template<typename... Dependency, typename Entity>
inline void disconnect(Sink<void(Registry<Entity> &, const Entity)> sink) {
sink.template disconnect<dependency<Entity, Dependency...>>();
}

enable_if for generic operator T()

Here's a sample program:
#include <type_traits>
#include <stdio.h>
template <typename X>
struct test
{
operator int() const { puts("?"); return 0; }
template <typename T, typename = typename std::enable_if<std::is_same<X, void*>::value, T>::type>
operator T() const { puts("T"); return 0; }
};
int main()
{
test<void*> t;
char* c = (char*)t;
switch (t)
{
case 0: break;
}
return 0;
}
And this is the error that g++-4.7 gives
user#user:~$ g++-4.7 -std=c++0x test.cpp
test.cpp: In function ‘int main()’:
test.cpp:13:14: error: ambiguous default typeconversion from ‘test<void*>’
test.cpp:13:14: error: candidate conversions include ‘template<class T, class> test::operator void*() const [with T = T; <template-parameter-2-2> = <template-parameter-1-2>; X = void*]’
g++ 4.6 compiles it without errors and different operators are actually called.
Is there a way to make this work under g++ 4.7?
UPDATE: actually it works in 4.6 without any enable_if at all... so the question still applies but I'm now not sure if enable_if will help.
If you add an explicit cast to int here:
switch ((int)t)
Then it should compile.
I think it's complaining about the conversion being ambiguous since there exists more than one type that can hold a 0 value.
I'm using g++ 4.8 though.
I found at least one "acceptable" solution:
#define switch(x) \
switch( (typename switch_type<__typeof(x)>::type)(x) )
which switch_type trait can be extended to resolve ambiguity for specific app-related types (property types).

Error passing arguments to template function with const qualifier

I have this code example:
#include <iostream>
#include <memory>
template <typename T>
void func1(T& value)
{
std::cout << "passed 1 ..." << std::endl;
}
template <template <typename> class T, typename U>
void func2(T<U>& value)
{
std::cout << "passed 2 ..." << std::endl;
}
int main()
{
std::auto_ptr<int> a;
const std::auto_ptr<int> ca;
// case 1: using func1
func1(a); // OK
func1(ca); // OK
// case 2: using func2
func2(a); // OK
func2(ca); // Compilation error
return 0;
}
In the first case the function 'func1' accepts a generic argument regardless of the qualifier, however the second case the function 'func2' fails when the argument has the const qualifier. Why this happens ?
This is the compilation error:
make all
Building file: ../src/Test2.cpp
Invoking: GCC C++ Compiler
g++ -O0 -g3 -Wall -c -fmessage-length=0 -MMD -MP -MF"src/Test2.d" -MT"src/Test2.d" -o "src/Test2.o" "../src/Test2.cpp"
../src/Test2.cpp: In function ‘int main()’:
../src/Test2.cpp:27: error: invalid initialization of reference of type ‘std::auto_ptr<int>&’ from expression of type ‘const std::auto_ptr<int>’
../src/Test2.cpp:11: error: in passing argument 1 of ‘void func2(T<U>&) [with T = std::auto_ptr, U = int]’
make: *** [src/Test2.o] Error 1
The problem is that in the case of func1, the compiler needs to deduce T and we get
T is std::auto_ptr<int> in the first call
T is const std::auto_ptr<int> in the second call
In both cases T is valid in itself.
Now for func2, the compiler needs to deduce T and U, where T is a template template parameter. What would be needed is:
T is std::auto_ptr, U is int in the first call
T is const std::auto_ptr, U is int in the second call
and there's your problem: T can not be const std::auto_ptr itself, as it combined a type-property const with a template std::auto_ptr which is not a valid type.

Compilation error on passing lambda expression to template function

Why can I not get the template function to accept the lambda expression?
After searching high and low -- I seriously though that this would work, but this C++ code;
template <typename F> int proc(const F& lam)
{
return lam();
}
void caller()
{
int i = 42;
int j = proc( [&i]()->int{ return i/7; } );
}
An I get the following errors;
$ g++ x.cc
x.cc: In function ‘void caller()’:
x.cc:11:44: warning: lambda expressions only available with -std=c++0x or -std=gnu++0x [enabled by default]
x.cc:11:46: error: no matching function for call to ‘proc(caller()::<lambda()>)’
x.cc:11:46: note: candidate is:
x.cc:3:27: note: template<class F> int proc(const F&)
I'm on linux using g++ 4.6.3 and 4.7.2
Does anybody know what I have to do to pass on a lambda expression as a parameter to a receiving template function? -- I don't want to use the std::function -- so my only alternative is to create an ugly functor pattern.
Update: Tried to declare the argument const F& lam, but without success.
Update2: added call to compiler...
Since the lambda isn't an lvalue, you need to pass it by const reference:
template <typename F> int proc(const F& lam)
Make sure to use -std=c++11 with g++ 4.7.2 or -std=c++0x with g++ 4.6.3.