I am facing compilation problem while running the following program:
I am calling non template member function inside template member function but getting the weird compilation errors.
#include <iostream>
#include <boost\shared_ptr.hpp>
class base
{
public:
base()
{
}
void fun2(boost::shared_ptr<int> &data)
{
std::cout << "This is fun2" << std::endl;
}
void fun3(boost::shared_ptr<double> &value)
{
std::cout << "This is fun3" << std::endl;
}
template <typename T>
void fun1(int switchParam,T &resonse)
{
std::cout << "This is fun1." << std::endl;
switch(switchParam)
{
case 0:
fun2(resonse);
break;
case 1:
fun3(resonse);
break;
}
}
};
void main()
{
boost::shared_ptr<int> myInt;
int switchParam = 0;
base b1;
b1.fun1(switchParam,myInt);
}
Getting the following compilation problem:
Error 1 error C2664: 'base::fun3' : cannot convert parameter 1 from 'boost::shared_ptr<T>' to 'boost::shared_ptr<T> &'
Any help will be appreciated.
No. You cannot do that. With second phase of template code compilation for any type the switch block has to be fully compiled by compiler. It will will fail to compile. You are mixing templates with runtime behavior of program. You better write a different function.
Note that switch is runtime, not compile time. When you call it as fun1(0) the compiler still has to compile it fully for int. It won't evaluate runtime switch statement and eliminate fun3, which takes shared_ptr<double>.
Related
I am building my program by using the latest Emscripten compiler.
It is based on Clang version 14. Actually it is a small test program which is the following:
#include <iostream>
struct Test {
template<typename T>
static inline void Dump(const T& value) {
std::cout << "[generic] = '" << value << "'\n";
}
template<>
static inline void Dump<std::string>(const std::string& value) {
std::cout << "[std::string] = '" << value << "'\n";
}
};
int main() {
std::string text = "hello";
Test::Dump(text);
return 0;
}
When I build it by Emscripten compiler I got the warning:
D:\em_test>emcc a.cpp
a.cpp:10:24: warning: explicit specialization cannot have a storage class
static inline void Dump<std::string>(const std::string& value) {
~~~~~~~ ^
1 warning generated.
If I just remove static keyword from void Dump<std::string> line
then there will be no warning. However, this code will cause compilation error in Visual Studio:
D:\em_test\a.cpp(17,11): error C2352: 'Test::Dump': illegal call of non-static member function
But this error is expected and clear.
I would like to write a cross-platform program.
So, I think I should simple disable this warning in Emscripten.
However, I can not find any Emscripten (which is based on clang version 14)
command line option for that!
And I am asking advice for that.
Actually I tried to use -Wno-static-inline-explicit-instantiation command line option but it did not help:
D:\em_test>emcc -Wno-static-inline-explicit-instantiation a.cpp
a.cpp:10:24: warning: explicit specialization cannot have a storage class
static inline void Dump<std::string>(const std::string& value) {
~~~~~~~ ^
1 warning generated.
However, I see in Clang version 13 user manual description about -Wstatic-inline-explicit-instantiation option but it is about a slightly another warning text.
Also it seems that Clang version 14 is not fully released, so, there is no public Clang version 14 user manual.
I can not find any Emscripten or Clang command line option to disable the above warning.
Could somebody help me?
Explicit specialization of (both static and non-static) function templates cannot be put into class definitions.
Just put it into the enclosing namespace(i.e somewhere after the class):
#include <iostream>
struct Test {
template <typename T>
static inline void Dump(const T& value) {
std::cout << "[generic] = '" << value << "'\n";
}
};
// Notice Test::
template <>
inline void Test::Dump<std::string>(const std::string& value) {
std::cout << "[std::string] = '" << value << "'\n";
}
int main() {
std::string text = "hello";
Test::Dump(text);
return 0;
}
inline is never necessary for in-class function definitions but it has different meaning for member variables.
inline for out-class is necessary in header files because the explicit specialization is not a template anymore.
This question already has an answer here:
Why class data members can't be initialized by direct initialization syntax?
(1 answer)
Closed 2 years ago.
In C++ I am having trouble passing parameters to the constructor for a template class.
it works when I instantiate from a function; but if I instantiate from a class, it gives "error C2059: syntax error: 'string'"
this is my very trimmed down example (names have been changed to protect the incent).
I am currently have std:latest enabled in Visual Studio 2019 and I've tried in 2017 as well.
#include <string>
#include <iostream>
template <class T>
class cap
{
public:
cap() : p(new(T)) {}
cap(const std::string& sfile, const std::string& sfunc, int line)
: m_file(sfile), m_func(sfunc), m_line(line) {}
~cap() {
delete p;
std::cout << "object freed: created in " << m_func << " line " << m_line << " of " << m_file;
}
private:
T* p{nullptr};
std::string m_file;
std::string m_func;
int m_line{0};
};
void foo()
{
cap<int> foo1("file", "func", 5); //<< compiles okay
}
class bar
{
cap<int> foo1("file", "func", 5); //<< "syntax error: 'string'"
};
IntelliSense says "expected a type specifier" when I hover the params used inside the class
My end goal is to have a macro to instantiate the object; passing in the location in source.The object thus knows where it was created.
#define CAP(type,var) cap<type> var(__FILE__, __func__, __LINE__)
CAP(somestruct, myvar);
// expands to:
cap<somestruct> myvar("file.cpp", "myfunc", 50);
For in-class initialization use the uniform initialization:
class bar
{
cap<int> foo1{"file", "func", 5};
};
#Alan has already provided a reference for why direct initialization using () don't work. It's also known as the C++ most vexed parse.
I used LLVM to code-gen, but I encounter a problem.
I have a class as below:
class AAA {
public:
template<typename Type>
void func(Type str) {
std::cout << str << std::endl;
}
void func2() {
std::cout << "hello" << std::endl;
}
};
And I have a llvm::ExecutionEngine* mJit;
Now I want to use addGlobalMapping to add the AAA::func and AAA::func2 to the llvm's global mapping.
// success
mJit->addGlobalMapping(fn_func2, reinterpret_cast<void*>(&AAA::func2));
// failed
// Because the `AAA::func` is an template function
mJit->addGlobalMapping(fn_func, reinterpret_cast<void*>(&AAA::func));
And then I tried one method as follow:
template<class Class, typename K>
using TemplateFunc = void (Class::*) (K);
TemplateFunc<AAA, int> myFunc = &AAA::func;
mJit->addGlobalMapping(fn_func, reinterpret_cast<void*>(myFunc));
But it came an error when link:
llvm::Finalize(): error: undefined reference to "void
AAA::func(int)". collect2: error: ld returned 1 exit status
So how to add a c++ template function to the llvm JIT global mapping ?
You get the linker error because you function AAA::func<int>() is never instantiated. You can solve this by explicitly instantiating the function for int:
template void AAA::func<>(int);
That forces the compiler to actually generate code.
I am trying to implement an execution pattern which takes any function and executes it with its own conditions/preparations. Regardless of this being a useful thing to do, it just doesn't work. It seems i can't access the template overload of the "Execute"-function (called in "main").
Specifically: Why can't i call the overloaded template function of Execute?
This is the full program:
#include "stdafx.h"
#include <functional>
class TransparentFunctionWrapper
{
public:
virtual void Execute(std::function<void()> executeFunction) = 0;
template<class C>
C Execute(std::function<C(void)> executeFunction) // template-overload of the abstract function which will implicitly call it
{
C ret;
Execute( // calls the abstract function with a lambda function as parameter
[ret, executeFunction](void) -> C // lambda declaraction
{ //
ret = executeFunction; // lambda body
}); //
return ret;
}
};
class ExampleExecutor : public TransparentFunctionWrapper
{
public:
virtual void Execute(std::function<void()> executeFunction)
{
printf("executed before.");
executeFunction();
printf("executed after.");
}
};
void DoStuff() {}
int ReturnStuff() { return -5; }
int main()
{
ExampleExecutor executor;
executor.Execute(DoStuff);
int i = executor.Execute<int>(ReturnStuff); // Why does this not work? ERROR: "type name is not allowed"
getchar();
return 0;
}
Note: Visual Studio marks
Execute<int>(ReturnStuff) // "int" is marked as Error: type name is not allowed
The compilation puts out the error
"type 'int' unexpected"
Thanks to everyone willing to help!
ExampleExecutor::Execute is not overriding TransparentFunctionWrapper::Execute, and it is hiding it in the executor.Execute<int> call.
You must explicitly call TransparentFunctionWrapper::Execute, as it is hidden by ExampleExecutor::Execute. Here's a possible way of doing that:
int i = executor.TransparentFunctionWrapper::Execute<int>(ReturnStuff);
live example on coliru
I am observing behavior in the below code which I cannot readily explain and would like to understand the theory of better. I cannot seem to find an online documentation source or existing question which covers this particular situation. For reference, I am using Visual Studio C++ 2010 to compile and run the following code:
#include <iostream>
using namespace std;
struct Bottom_Class
{
template<typename This_Type>
void Dispatch()
{
// A: When this comment is removed, the program does not compile
// citing an ambiguous call to Print_Hello
// ((This_Type*)this)->Print_Hello();
// B: When this comment is removed instead, the program compiles and
// generates the following output:
// >> "Goodbye from Top Class!"
// ((This_Type*)this)->Print_Goodbye<void>();
}
void Print_Hello() {cout << "Hello from Bottom Class!" << endl;}
template<typename This_Type>
void Print_Goodbye() {cout << "Goodbye from Bottom Class!" << endl;}
};
struct Top_Class
{
void Print_Hello() {cout << "Hello from Top Class!" << endl;}
template<typename This_Type>
void Print_Goodbye() {cout << "Goodbye from Top Class!" << endl;}
};
template<typename Top_Type,typename Bottom_Type>
struct Merged_Class : public Top_Type, public Bottom_Type {};
typedef Merged_Class<Top_Class,Bottom_Class> My_Merged_Class;
void main()
{
My_Merged_Class my_merged_object;
my_merged_object.Dispatch<My_Merged_Class>();
}
Why does this work differently for the templated member function vs. non-templated member function cases ?
How does the compiler decide (in the templated case) that Top_Class::Print_Goodbye() is the appropriate overload rather than Bottom_Class::Print_Goodbye() ?
Thank you in advance for your consideration.
Both comments (AFAIK correctly) generate compilation error with GCC 4.6.3. May be the Microsoft compiler is doing something incorrect.
➜ scratch g++ -O2 templ.cc
templ.cc: In member function ‘void Bottom_Class::Dispatch() [with This_Type = Merged_Class<Top_Class, Bottom_Class>]’:
templ.cc:42:48: instantiated from here
templ.cc:16:9: error: request for member ‘Print_Goodbye’ is ambiguous
templ.cc:22:10: error: candidates are: template<class This_Type> void Bottom_Class::Print_Goodbye()
templ.cc:30:10: error: template<class This_Type> void Top_Class::Print_Goodbye()
In the Dispatch method, This_Type is the same as My_Merged_Class. The My_Merged_Class has two methods with the names of Print_Hello, of course the compiler is going to have problems to distinguish between them.
The call to Print_Hello in Dispatch, after template replacement, looks like this:
((My_Merged_Class*)this)->Print_Hello();
I hope the above substitution helps you see better why there is an ambiguity. The same problem should actually occur for Print_Goodbye, but it might be a bug in the compiler you are using that lets it through.