So I've found a variety of articles and posts saying that there is no way to convert typename to string but I haven't found one about the opposite. I have a template of a function with specializations:
template <typename T>
void foo(T sth) {}
template <>
void foo<int>(int sth) {}
...
and I'm reading from a file constructed like this:
int 20
double 12.492
string word
Is there a way to call the correct specialization of foo() depending on the content of the file?
Yes there is, but it requires manual code and that you know all the types that are going to appear in the file. That's because templates are compile time constructs and they cannot be instantiated at runtime.
You can always use the preprocessor or other tricks to try and reduce the boilerplate if you want to.
void callFoo(std::string type, std::any arg) {
if (type == "int")
foo<int>(std::any_cast<int>(arg));
else if (type == "double")
foo<double>(std::any_cast<double>(arg));
else if (type == "string")
foo<std::string>(std::any_cast<std::string>(arg));
}
Of course, this requires that you pass in the correct type (no implicit conversions!). I don't see any way to avoid that.
To be honest, I am not sure about understanding your question. As I interpret it, I believe that you do not need a kind of dispatcher in running time neither to compute a string containing the type name. Simply you write a general template function that calls a special template wrapper that disambiguates the call to foo() according to the type. You require that the specialized foo() receives a second special parameter (the_type<T>) which is used for disambiguating.
Here a full and operating demo:
# include <string>
# include <iostream>
using namespace std;
template<class T> struct the_type { using type = T; };
template <typename T>
void foo(const T par)
{
foo(par, the_type<T>());
}
void foo(int par, the_type<int>)
{
cout << "int " << par << endl;
}
void foo(double par, the_type<double>)
{
cout << "double " << par << endl;
}
void foo(const string & par, the_type<string>)
{
cout << "string " << par << endl;
}
void foo(const char * par, the_type<const char*>)
{
cout << "char* " << par << endl;
}
int main()
{
foo(20);
foo(12.492);
foo("word");
foo(string("word"));
}
whose output is:
int 20
double 12.492
char* word
string word
If you need another specialization, then you simply define it. In some cases, you will have to explicitly to define the specialization as the template parameter.
You could use macro manips for avoiding repetitive things. For example, given that foo() structure is the same, you could encapsulate it in a macro. Something like this:
# define GENFOO(type_name) \
void foo(type_name par, the_type<type_name>) \
{ \
cout << #type_name " " << par << endl; \
}
GENFOO(int);
GENFOO(double);
GENFOO(string)
However, I would say that each specialized version of foo() would not be so similar.
Related
So I've found a variety of articles and posts saying that there is no way to convert typename to string but I haven't found one about the opposite. I have a template of a function with specializations:
template <typename T>
void foo(T sth) {}
template <>
void foo<int>(int sth) {}
...
and I'm reading from a file constructed like this:
int 20
double 12.492
string word
Is there a way to call the correct specialization of foo() depending on the content of the file?
Yes there is, but it requires manual code and that you know all the types that are going to appear in the file. That's because templates are compile time constructs and they cannot be instantiated at runtime.
You can always use the preprocessor or other tricks to try and reduce the boilerplate if you want to.
void callFoo(std::string type, std::any arg) {
if (type == "int")
foo<int>(std::any_cast<int>(arg));
else if (type == "double")
foo<double>(std::any_cast<double>(arg));
else if (type == "string")
foo<std::string>(std::any_cast<std::string>(arg));
}
Of course, this requires that you pass in the correct type (no implicit conversions!). I don't see any way to avoid that.
To be honest, I am not sure about understanding your question. As I interpret it, I believe that you do not need a kind of dispatcher in running time neither to compute a string containing the type name. Simply you write a general template function that calls a special template wrapper that disambiguates the call to foo() according to the type. You require that the specialized foo() receives a second special parameter (the_type<T>) which is used for disambiguating.
Here a full and operating demo:
# include <string>
# include <iostream>
using namespace std;
template<class T> struct the_type { using type = T; };
template <typename T>
void foo(const T par)
{
foo(par, the_type<T>());
}
void foo(int par, the_type<int>)
{
cout << "int " << par << endl;
}
void foo(double par, the_type<double>)
{
cout << "double " << par << endl;
}
void foo(const string & par, the_type<string>)
{
cout << "string " << par << endl;
}
void foo(const char * par, the_type<const char*>)
{
cout << "char* " << par << endl;
}
int main()
{
foo(20);
foo(12.492);
foo("word");
foo(string("word"));
}
whose output is:
int 20
double 12.492
char* word
string word
If you need another specialization, then you simply define it. In some cases, you will have to explicitly to define the specialization as the template parameter.
You could use macro manips for avoiding repetitive things. For example, given that foo() structure is the same, you could encapsulate it in a macro. Something like this:
# define GENFOO(type_name) \
void foo(type_name par, the_type<type_name>) \
{ \
cout << #type_name " " << par << endl; \
}
GENFOO(int);
GENFOO(double);
GENFOO(string)
However, I would say that each specialized version of foo() would not be so similar.
I'm wondering how exactly this code works in detail (e.g. how is it able to directly access the value of TYPE).
I saw this code in a larger codebase (which is non-public, so the example is paraphrased). I've never seen this specific use-case. Is passing a template parameter like this common? Does it have a specific name/is this an idiom/pattern? When would you use this and why?
#include <iostream>
namespace FileA
{
struct Foo
{
enum TYPE
{
ENTRY,
};
void callme()
{
std::cout << "Foo\n";
}
};
}
namespace FileB
{
template <typename T>
void fun(T& obj)
{
std::cout << T::ENTRY << "\n";
obj.callme();
}
}
int main()
{
FileA::Foo f;
FileB::fun(f);
}
This will print:
0
Foo
a template is a kind of macro in the general sense of the term, so if you "expand" FileB::fun(f); T is replaced by the type of f being FileA::Foo and it is like if you have :
void fun(FileA::Foo& obj)
{
std::cout << FileA::Foo::ENTRY << "\n";
obj.callme();
}
because FileA::Foo::ENTRY is 0 the std::cout writes 0, then you apply FileA::Foo::callme() whose prints Foo
Warning, a template is much more than that, it is just a very simplified explanation of how that example works and produces the outputs, do not take it literally please ^^
So I've found a variety of articles and posts saying that there is no way to convert typename to string but I haven't found one about the opposite. I have a template of a function with specializations:
template <typename T>
void foo(T sth) {}
template <>
void foo<int>(int sth) {}
...
and I'm reading from a file constructed like this:
int 20
double 12.492
string word
Is there a way to call the correct specialization of foo() depending on the content of the file?
Yes there is, but it requires manual code and that you know all the types that are going to appear in the file. That's because templates are compile time constructs and they cannot be instantiated at runtime.
You can always use the preprocessor or other tricks to try and reduce the boilerplate if you want to.
void callFoo(std::string type, std::any arg) {
if (type == "int")
foo<int>(std::any_cast<int>(arg));
else if (type == "double")
foo<double>(std::any_cast<double>(arg));
else if (type == "string")
foo<std::string>(std::any_cast<std::string>(arg));
}
Of course, this requires that you pass in the correct type (no implicit conversions!). I don't see any way to avoid that.
To be honest, I am not sure about understanding your question. As I interpret it, I believe that you do not need a kind of dispatcher in running time neither to compute a string containing the type name. Simply you write a general template function that calls a special template wrapper that disambiguates the call to foo() according to the type. You require that the specialized foo() receives a second special parameter (the_type<T>) which is used for disambiguating.
Here a full and operating demo:
# include <string>
# include <iostream>
using namespace std;
template<class T> struct the_type { using type = T; };
template <typename T>
void foo(const T par)
{
foo(par, the_type<T>());
}
void foo(int par, the_type<int>)
{
cout << "int " << par << endl;
}
void foo(double par, the_type<double>)
{
cout << "double " << par << endl;
}
void foo(const string & par, the_type<string>)
{
cout << "string " << par << endl;
}
void foo(const char * par, the_type<const char*>)
{
cout << "char* " << par << endl;
}
int main()
{
foo(20);
foo(12.492);
foo("word");
foo(string("word"));
}
whose output is:
int 20
double 12.492
char* word
string word
If you need another specialization, then you simply define it. In some cases, you will have to explicitly to define the specialization as the template parameter.
You could use macro manips for avoiding repetitive things. For example, given that foo() structure is the same, you could encapsulate it in a macro. Something like this:
# define GENFOO(type_name) \
void foo(type_name par, the_type<type_name>) \
{ \
cout << #type_name " " << par << endl; \
}
GENFOO(int);
GENFOO(double);
GENFOO(string)
However, I would say that each specialized version of foo() would not be so similar.
I am just starting to teach myself C++ and am having a hard time with function parameter passing. For example I am using my own print function where you simply put the string into the parameters and it logs it to the console.
//Print Function
void print(std::string message = "") {
std::cout << message << std::endl;
}
However because I declare it as a std::string variable if I pass it a number it will not print it. Ultimately I would like to make an input and print system like in Python. How to I go about this? Is there a way to convert the parameters to string? Or some other solution. Another function with similar problems is my input function:
//Input function (Enter does not work without text, space is not text)
std::string input(const char* message = "") {
std::cout << message;
std::string x;
std::cin >> x;
return x;
}
This does not allow the return to be an int witch makes calculations using the input harder. Any help is appreciated thanks in advance!
~ Moses
Besides template, if your compiler supports C++14, You can also use auto with lambda function. You can just write all these inside the main function.
auto print = [](const auto& message) {std::cout << message << std::endl;};
print(1); //1
print("AAA"); //AAA
Note that, unlike Python, when you want to print something, you don't need to convert it to a string first. As long as the thing you want to print has overloaded cout, You can simply cout it. And using template or auto doesn't change the fact that everything in C++ is statically typed, it's just that the compiler will create the different versions of overload functions for you automatically.
EDIT
As #Peter pointed out in the comment section, saying "cout is something that can be overloaded is flat-out wrong", and more accurate to say overloading the operator<< for the ostream and the corresponding class
Can++ templates are useful there.
//Print Function
template <typename T>
void print(const T& message) {
std::cout << message << std::endl;
}
void print() {
std::cout << std::endl;
}
Note, I removed a default argument value and used overloaded function. With passed empty argument type of template parameter can not be deduced. print does not work with containers and you need more efforts to print containers, in Python it works from box.
//Input function (Enter does not work without text, space is not text)
template <typename T>
T input(const char* message = "")
{
std::cout << message;
T x;
std::cin >> x;
return x;
}
Usage: int n = input<int>("Input number:");.
Alternatively I discovered a way to do this without using lambda:
void print(int message) {
std::cout << message << std::endl;
};
void print(float message) {
std::cout << message << std::endl;
};
void print(std::string message) {
std::cout << message << std::endl;
};
By making multiple functions with the same name it will use what ever one works, so any input (3.14, 8, "Hello") will all work and use corresponding function.
Currently, I encounter some difficulty in overloading a certain function. here's my code:
template<typename Value>
bool process(Value thisValue)
{
return processAccordingToTheType(thisValue);
}
So, there are two overloaded function of processAccordingToTheType:
bool processAccordingToTheType(int thisValue){}
bool processAccordingToTheType(string thisValue){}
when I try to compile it, it said:
error C2665: 'processAccordingToTheType' : none of the 2 overloads could convert all the argument types
what do I need to do?
Update:
int main()
{
int i = 1;
process <int> (i);
}
From your sample code I understand you need two things to be done:
Call a type specific process function
Restrict these calls to string and int types
Wrapping the processAccordingToType function inside process<T> is completely redundant: process<T> actually means 'process according to type'. The keyword here is 'template specialization'. You need to specialize your 'process according to type' method for int and string.
You can do this as below:
#include <iostream>
using namespace std;
template<typename T>
bool process(T t)
{
// call a Compile-Time Assertion
cout << "I don't want this to be called." << endl;
}
template <>
bool process<int>(int i)
{
cout << "process(int) called." << endl;
}
template <>
bool process<string>(string s)
{
cout << "process(string) called." << endl;
}
int main()
{
process(1);
process(string("s"));
process(1.0d);
}
Output:
process(int) called.
process(string) called.
I don't want this to be called.
Ideally, you want to prevent the users of your API calling process with other types. Allowing them to call and handling this at runtime (like it's done in my example) is not acceptable. You achieve this with Compile-Time Assertions. Read "Modern C++ Designs" by Andrei Alexandrescu for ways of doing that.
Look into template specialization. Does what you're looking for without deferring to another function based on type.
http://www.cprogramming.com/tutorial/template_specialization.html
You can overload function templates with either a non-template function or another template function. Make sure that whatever you do, you test incrementally as template errors are notoriously hard to understand.
http://www.cplusplus.com/doc/tutorial/templates/
#include <iostream>
using namespace std;
template <typename Value>
bool processAccordingToTheType( Value thisValue ){
cout << "Generic Type" << endl;
return false;
}
bool processAccordingToTheType(int thisValue){
cout << "int type" << endl;
return true;
}
template <typename Value>
bool process( Value thisValue ){
return processAccordingToTheType(thisValue);
}
int main( int argc, char* argv[] ){
cout << process( 1 ) << endl;
cout << process( "Hello" ) << endl;
return 0;
}