compile-time check with const char* (nullptr) - c++

I have a template class that takes a string literal as parameter. The code works fine - but I've got one question, whether it is possible to use compile-time check to skip the generating of if (S) or else block body at all? (Something like the __if_exists or #if, traits, etc). I understand that I could have a specialized A<nullptr> that defines a different print() function, but also want to know whether there's other (more simple) ways of doing this. Thanks!
template<char const* S = nullptr>
class A
{
public:
void print()
{
if (S)
cout << S << endl;
else
cout << "nullptr" << endl;
}
};

In your case, can't you set the default value of S as "nullptr" or any other constant string? Of course, this works when you don't actually need S to be NULL, but it will skip the if check.

add a function,
constexpr const char* getStr(){
return S? S : "null";
}
then it becomes,
void print(){
std::cout << getStr() << std::endl;
}

Related

Types should be the same but are not

I am not sure I understand why the first test evaluates to true and the second to false. I know that the information from typeid().name() is usually not reliable, but my main problem is with the typeid itself. I don't understand why the type of *test is not Location<1>, or what else is wrong. Any thoughts? Is there same wrapper around a type here that I don't see? Thanks in advance, and apologies if the answer is obvious.
#include <iostream>
#include <utility>
#include <typeinfo>
class LocationAbstract
{
virtual void get_() = 0;
};
template<int i>
class Location : public LocationAbstract
{
public:
static constexpr int test = i;
virtual void get_() override
{
return;
}
};
template <int i>
Location<i> LocationGenerator()
{
Location<i> test{};
return test;
}
int main()
{
LocationAbstract *table[10];
table[0] = new decltype(LocationGenerator<0>());
table[1] = new decltype(LocationGenerator<1>());
Location<1> *test;
try
{
std::cout << "Casting\n";
test = dynamic_cast<Location<1>*>(table[1]);
}
catch (std::bad_cast &e)
{
std::cout << "Bad cast\n";
}
// test1, evaluates to true
std::cout << (typeid(*test) == typeid(*dynamic_cast<Location<1>*>(table[1]))) << "\n";
std::cout << typeid(*test).name() << "\n";
std::cout << typeid(*dynamic_cast<Location<1>*>(table[1])).name() << "\n----\n";
// test2, why does this evaluate to false while the above evaluates to true ?
std::cout << (typeid(Location<1>()) == typeid(*dynamic_cast<Location<1>*>(table[1]))) << "\n";
std::cout << typeid((Location<1>())).name() << "\n";
std::cout << typeid(*dynamic_cast<Location<1>*>(table[1])).name() << "\n";
auto test1 = Location<1>();
auto test2 = *dynamic_cast<Location<1>*>(table[1]);
std::cout << typeid(test1).name() << " and " << typeid(test2).name() << "\n";
return 0;
}
An extra set of () makes all the difference here. In typeid(Location<1>()) and typeid((Location<1>())), Location<1>() actually means two totally different things.
In typeid(Location<1>()), Location<1>() is interpreted as a function type that returns a Location<1> and takes no parameters.
In typeid((Location<1>())), Location<1>() is interpreted as value-initializing an anonymous Location<1> object.
The typeid operator can work on either types or expressions. That is, you can say typeid(int) as well as typeid(42). Since Location<1>() can be interpreted as a type, the language does so. (Location<1>()) cannot be interpreted as a type though, so it must be interpreted as an expression. The only thing Location<1>() can mean as part of an expression is to value-initialize an anonymous Location<1> object, so typeid gives you the type of that object.
Let this be yet another reason to prefer uniform-initialization syntax when creating temporary objects; Location<1>{} would not have this ambiguity.
Examine these two lines:
std::cout << (typeid(Location<1>()) == typeid(*dynamic_cast<Location<1>*>(table[1]))) << "\n";
std::cout << typeid((Location<1>())).name() << "\n";
In the first line, you use typeid(Location<1>()). typeid can take types as well as expressions, and Location<1>() is a function type with no parameters and a return type of Location<1>.
So why does the name print the same? That's because of the second line: typeid((Location<1>())). By wrapping the argument in parentheses, it is no longer a valid type, so it is treated as an expression and the name of typeid(Location<1>) is printed. Removing the extra parentheses prints F8LocationILi1EEvE under the same mangling scheme.
To avoid the ambiguity, you can also use the type directly (typeid(Location<1>)) or use braces: typeid(Location<1>{})).

"Converting" string to type [duplicate]

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.

Is there anyway that I can determine whether the construct function is exist?

#include <iostream>
template<typename _OutType, typename _InType>
struct ConvertClass
{
_OutType operator()(_InType src)
{
return _OutType(src);
}
};
class OutClass
{
public:
OutClass(std::string str)
{
std::cout << "construct function works well!" << std::endl;
}
};
int main()
{
ConvertClass<OutClass, int>()(20); // this is wrong, because the OutClass only have one construct which takes the std::string type parameter.
// ConvertClass<OutClass, std::string>()(std::string("Hello!"));
/*
if (...) // So I wonder if there is any way that we can know whether the construct function is exists or not before we call the OutClass(int i) function
{
std::cout << "there is no such construct function of OutClass to take that parameter type" << std::endl;
return -1;
}
else
{
std::cout << "construct function works well!" << std::endl;
return 0;
}
*/
}
My Problem:
I know the main function is definitely wrong for the OutClass don't have the construct function OutClass(string str).
I wonder if there is a way only to change the Comment 1 section, the template class to make this file be compiled and linked successfully.
My English is not good, hoping you guys don't mind!
Thank you !
to my knowledge there is not runtime checking if given class is constructible using argument of given type
as said in my previous answer you can resort to Concepts and check the types at compiletime, but if clause does not work at compile time
To me it looks like the best solution would be indeed making a template class out of OutClass, then you have a single class with serves diverse purposes, dependent on you needs
one more edit to your code, I see that you pass the _OutType and _InType to your template.
In the setting where we have the following class template
template<class srcType>
class OutType:{
srcType src;
public:
OutType(srcType src) : src(src) {std::cout << "constructor works well!" << std::endl;}
}
then while invoking the class ConvertClass:
auto val = ConvertClass<OutClass<std::string>, std::string>()(std::string("Hello!"));
and also this will work:
auto val = ConvertClass<OutClass<int>, int>(20);
however, since operator() is not a static method you need first to construct object of class ConvertClass
In c++20 or even in c++17 you can in fact check if OutClass is constructible from int:
so your if clause should look like this
if(std::is_constructible<OutClass, int>::value) {
std::cout << "all is well" << std::endl;
}else{
std::cout << "you can't construct OutClass from int" << std::endl;
}
you can make the the following class template from the OutClass
template<class SrcType>
class OutClass {
SrcType src;
public:
OutClass(SrcType src) : src(src) {}
}
then in your code
return OutType<InType>(src);
if you need to check what the classes passed as template arguments actually can do (if they are arithmetic or additive or copy constructible e.g.) use Concepts from the C++20 standard

Converting parameters when passing to functions (c++)

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.

C/C++ macro expanding to argument, argument as string

I have many variables that are named the same as elements in an engineering specification document so the string version of the name is also useful.
I find myself using a macro like this a lot:
#define MACRO(a) a, #a
Typical usage is:
void someFunction(int a, const char *name);
someFunction(MACRO(meaningfully_named_variable));
My question is threefold:
Is there a better way of doing this?
Is a similar macro available in Boost or other libraries?
If not, how could I refine and rename this to make it clear and useful?
Edit
I should have said that the above is a minimal example. The function might have other parameters and the named entity might be a data member or perhaps even a function itself.
Another extension I'm considering for C++ is a class NamedRef that could receive the contents of the macro.
template <typename T>
struct NamedRef
{
NamedRef(T *t, const char *name) : t(t), name(name) { }
T *t;
const char *name;
};
template <typename T>
NamedRef<T> namedRef(T &t, const char *name)
{
return NamedRef<T>(&t, name);
}
#define WITH_NAME(a) a, #a
// more sophisticated usage example
void otherFunction(double, NamedRef<int>, bool);
otherFunction(0.0, namedRef(object.WITH_NAME(meaningful_member_name)), false);
You could take it a step further:
#define SOMEFUNCTION(a) somefunction(a, #a)
However, this is only useful if you call the same function alot. Otherwise, I don't think there is any better way than your example. Of course, you should change the name of the macro to something more meaningful though, like ARGUMENTS or something.
You are likely to find that XMACROs are useful for this kind of work.
#define someFunction(a) if (1) stringized_someFunction((a), #a ); else (void)0
void stringized_someFunction(int a, const char* name);
The if (1) stuff wraps up the macro so that it won't mess (usually) with loops, branches, if statements, etc.
You would then call your function like so:
int r = 4;
someFunction(r);
You only really add one extra line for each "function declaration." If the C preprocessor allowed multiple steps you could wrap it all up into one, but alas, it doesn't.
I forgot because I hope it's obvious that you'd need to write your function:
void stringized_someFunction(int a, const char* name)
{
// Do stuff here
}
Anyhow it should be a lot easier and prettier to read that way.
As Jesse answered,
you can write like this:
void function1(int a, const char* name)
{
cout << "a: " << a << endl;
cout << "name: " << name << endl;
}
void function2(double d, const char* name, const char *str)
{
cout << "d: " << d << endl;
cout << "name: " << name << endl;
cout << "str: " << str << endl;
}
#define MACRO(functionName, a) functionName(a, #a)
#define MACRO2(functionName, a, ...) functionName(a, #a, __VA_ARGS__)
int main()
{
int a = 10;
MACRO(function1, a);
double d = 10.5;
MACRO2(function2, d, "Hello world");
return 0;
}
If you have more arguments to pass, you can use MACRO2 that uses variable arguments. You will have to pass the function name accordingly.