why this code call general template function in GCC? - c++

#include<iostream>
using namespace std;
// define the general compare template
template <class T>
int compare(const T& t1, const T& t2) {
cout<< "Common_T"<<endl;
return 0;
}
template<>
int compare<const char*>( const char * const& s1,
const char * const& s2)
{
cout<< "Special_T"<<endl;
return 0;
}
typedef const char char6[6];
template<>
int compare<char6>(const char6& s1,const char6& s2)
{
cout << "Special_Char6_T" << endl;
return 0;
}
int main() {
int i = compare("hello" , "world");
}
the result is:
Common_T
My question is: why don't output "Special_Char6_T"???

This is the correct template specialization that matches your c strings.
typedef char char6[6];
template<> int compare<char6>(char6 const &s1,char6 const &s2)
{
cout << "Special_Char6_T" << endl;
return 0;
}

Intuitively, because the dimension of arrays is not part of their type. That dimension matters only for variables and fields. So both
char hello[6]="hello";
and
char longstring[] = "a very very long string should be here";
have both the same type char[]
and
typedef char t1[6];
and
typedef char t2[];
are aliases for the "same" type.
(You could look at the mangled function names to have a clue)

Related

Templated snprintf

I need to convert some numbers (integers and doubles) into std::strings, and for performance reasons cannot use stringstream (we found it to be very slow when used concurrently)
It would be nice to be able to do something like
template<typename T>
static const std::string numberToString(T number)
{
char res[25];
// next line is a bit pseduo-y
snprintf(res, sizeof(res), "%T", number);
return string(res);
}
But I'm not really sure how is the best way to achieve this?
Here's one idea. Use:
template<typename T>
static const std::string numberToString(T number)
{
char res[25];
snprintf(res, sizeof(res), getPrintfFormat<T>(), number);
return res;
}
Sample program:
#include <iostream>
#include <cstdio>
#include <string>
template <typename T> struct PrintfFormat;
template <> struct PrintfFormat<int>
{
static char const* get() { return "%d"; }
};
template <> struct PrintfFormat<float>
{
static char const* get() { return "%f"; }
};
template <> struct PrintfFormat<double>
{
static char const* get() { return "%f"; }
};
template <typename T>
char const* getPrintfFormat()
{
return PrintfFormat<T>::get();
}
template<typename T>
static const std::string numberToString(T number)
{
char res[25];
snprintf(res, sizeof(res), getPrintfFormat<T>(), number);
return res;
}
int main()
{
std::cout << numberToString(10) << std::endl;
std::cout << numberToString(10.2f) << std::endl;
std::cout << numberToString(23.456) << std::endl;
}
Output:
10
10.200000
23.456000
It also provides a level of type safety. With the posted code, using
std::cout << numberToString('A') << std::endl;
will result in a compile time error.

Concatenate compile-time strings in a template at compile time?

Currently I have:
template <typename T> struct typename_struct<T*> {
static char const* name() {
return (std::string(typename_struct<T>::name()) + "*").c_str();
}
};
I wonder if I can avoid the whole bit where I'm forced to allocate a string to perform the concatenation.
This is all happening at compile time, i.e. I intend to get the string "int****" when I reference typename_struct<int****>::name(). (Do assume that I have declared a corresponding specialization for int which returns "int")
As the code is written now, does the compiler do the concatenation with std::string during compile time only? (I would be okay with that) Or does such a call result in 4 std::string based concatenations at runtime? (I would not be okay with that)
You could use something like this. Everything happens at compile time. Specialize base_typename_struct to define your primitive types.
template <const char* str, int len, char... suffix>
struct append {
static constexpr const char* value() {
return append<str, len-1, str[len-1], suffix...>::value();
}
};
template <const char* str, char... suffix>
struct append<str, 0, suffix...> {
static const char value_str[];
static constexpr const char* value() {
return value_str;
}
};
template <const char* str, char... suffix>
const char append<str, 0, suffix...>::value_str[] = { suffix..., 0 };
template <typename T>
struct base_typename_struct;
template <>
struct base_typename_struct<int> {
static constexpr const char name[] = "int";
};
template <typename T, char... suffix>
struct typename_struct {
typedef base_typename_struct<T> base;
static const char* name() {
return append<base::name, sizeof(base::name)-1, suffix...>::value();
}
};
template <typename T, char... suffix>
struct typename_struct<T*, suffix...>:
public typename_struct<T, '*', suffix...> {
};
int main() {
cout << typename_struct<int****>::name() << endl;
}
Alternative way without using recursive templates (but requires C++14):
#include <utility>
template<int...I> using is = std::integer_sequence<int,I...>;
template<int N> using make_is = std::make_integer_sequence<int,N>;
constexpr auto size(const char*s) { int i = 0; while(*s!=0){++i;++s;} return i; }
template<const char*, typename, const char*, typename>
struct concat_impl;
template<const char* S1, int... I1, const char* S2, int... I2>
struct concat_impl<S1, is<I1...>, S2, is<I2...>> {
static constexpr const char value[]
{
S1[I1]..., S2[I2]..., 0
};
};
template<const char* S1, const char* S2>
constexpr auto concat {
concat_impl<S1, make_is<size(S1)>, S2, make_is<size(S2)>>::value
};
Example:
constexpr const char a[] = "int";
constexpr const char c[] = "**";
#include <iostream>
int main()
{
std::cout << concat<a,b> << '\n';
}
append characters to string can also be implemented like this, by replacing the second const char* parameter with char....
I'm not sure of what you're searching for but I believe you're interested in a combination of typeid and name-demangling (which compiler are you using?)
In gcc it would be something like
#include<iostream>
#include <string>
#include <typeinfo>
#include <cstdlib>
#include <memory>
#include <cxxabi.h>
using namespace std;
std::string demangle(const char* name) {
int status = -4; // some arbitrary value to eliminate the compiler warning
// enable c++11 by passing the flag -std=c++11 to g++
std::unique_ptr<char, void(*)(void*)> res {
abi::__cxa_demangle(name, NULL, NULL, &status),
std::free
};
return (status==0) ? res.get() : name ;
}
template <typename T> struct typename_struct {
static std::string name() {
std::string typeName = typeid(T).name();
return demangle(typeName.c_str());
}
};
int main(){
cout << typename_struct<int****>::name(); // Prints "int****"
return 0;
}
http://ideone.com/nLsFF0
Sources: https://stackoverflow.com/a/4541470/1938163
As for your question: those aren't constexpr constructs, thus the evaluation happens at runtime although the templated parameters and code are instantiated at compile-time.
Using templates doesn't mean every instruction contained in there will be executed and resolved at "compile-time".
I believe you can't achieve this whole bunch of stuff at compile-time since there are de-mangling functions (ABI-specific) involved. If I interpreted your question wrong please let me know.
#include <iostream>
//
***************************************************************************
template<const char* S1, const char* S2, size_t I1 = 0, size_t I2 = 0, char = S1[I1], char = S2[I2], char... Chars>
struct Concat : Concat<S1, S2, I1 + 1, I2, S1[I1 + 1], S2[I2], Chars..., S1[I1]>
{
};
// ****************************************************************************
template<const char* S1, const char* S2, size_t I1, size_t I2, char C2, char... Chars>
struct Concat<S1, S2, I1, I2, 0, C2, Chars...> : Concat<S1, S2, I1, I2 + 1, 0, S2[I2 + 1], Chars..., S2[I2]>
{
};
// ****************************************************************************
template<const char* S1, const char* S2, size_t N1, size_t N2, char... Chars>
struct Concat<S1, S2, N1, N2, 0, 0, Chars...>
{
static constexpr const char Text[] = { Chars... , 0 };
};
// ****************************************************************************
static constexpr const char A[] = "123";
static constexpr const char B[] = "456";
// ****************************************************************************
int main(int argc, char* argv[]){
std::cout << Concat<A, B>::Text << std::endl;
return 0;
}

Using const char** with Template Specialization

I am trying to write a template specialization for a function that returns the maximum value of an array of numeric values (general version) or the longest c-string of an array of c-strings (specialization). If I do not use const-ness, my function prototypes look like this
template <typename T>
T maxn(T* my_Tptr, unsigned int n);
template <>
char* maxn <char*> (char** my_cstrings, unsigned int n);
and my code compiles.
However, if I try to use const-ness, my function prototypes look like this,
template <typename T>
T maxn(const T* my_Tptr, unsigned int n);
template <>
char* maxn <char*> (const char** my_cstrings, unsigned int n);
my code does not compile, and the compiler (gcc) prints this error:
error: template-id 'maxn' for 'char* maxn(const char**, unsigned int)' does not match any template declaration.
Where am I going wrong?
The problem is in the constness. If you look closely const T* my_Tptr means my_Tptr is a pointer to const T. But const char** my_Tptr means Tptr is a pointer to pointer to const char. So the type moves from pointer to const T to pointer to pointer to const T. If you make it char* const* my_Tptr* then it will work, since then the type will be pointer to const char pointer. The specialization is pointer to const T*->pointer to const char*
Not sure what is the whole logic behind it but if you change your template definition to say that you are expecting pointers that will help:
template <typename T>
T* maxn(const T** my_Tptr, unsigned int n);
template <>
char* maxn(const char** my_cstrings, unsigned int n);
You might provide several overloads for the char-case to resolve the issue:
#include <iostream>
#include <stdexcept>
template <typename T>
T maxn(const T* const data, unsigned int n) {
throw std::logic_error("Failure");
}
const char* maxn(const char * const * data, unsigned int n) {
return "Success";
}
inline const char* maxn(const char** data, unsigned int n) {
return maxn(static_cast<const char * const *>(data), n);
}
inline const char* maxn(char* const * data, unsigned int n) {
return maxn(static_cast<const char * const *>(data), n);
}
inline const char* maxn(char** data, unsigned int n) {
return maxn(static_cast<const char * const *>(data), n);
}
int main() {
const char* a[] = { "A", "B", "C" };
std::cout << maxn((const char * const *)a, 3) << '\n';
std::cout << maxn((const char **)a, 3) << '\n';
std::cout << maxn((char * const *)a, 3) << '\n';
std::cout << maxn((char**)a, 3) << '\n';
}
This compiles fine:
template <>
char* maxn(char* const* my_cstrings, unsigned int n);
It accepts a pointer to a const char pointer like specified in the base template.

c++ numerical parser using template metaprogramming

i have been working for around 4 hours tryng to find a way that this code compile:
template < char ... RHS, unsigned int i>
struct t {
static const char s[] = t<' ', char(i+'0'), RHS, i-1>::s;
};
template <char ... RHS >
struct t<RHS, 0> {
static const char s[] = {'0', RHS, '\0'};
};
void main() {
std::cout << t<5>::s; // {'0',' ','1',' ','2',' ','3',' ','4',' ','5','\0'}
}
i from another post, that i dont have the link, but this code is tryng to parser a number to char at compile time. any help why this code is not compiling?
thx in advance!
#include <iostream>
// template parameter pack needs to at the end
template < unsigned int i, char ... RHS >
struct t {
// can't copy-initialize an array from another array
constexpr static char const* s()
{ return t<i-1, ' ', char(i+'0'), RHS...>::s(); };
};
template <char ... RHS >
struct t<0, RHS...> {
// can't initialize a const array inside the class,
// need to use `constexpr`
constexpr static char arr[] = {'0', RHS..., '\0'};
constexpr static char const* s()
{ return arr; }
};
// need to define the array variable, it's ODR-used
template <char ... RHS >
constexpr char t<0, RHS...>::arr[];
int main() {
std::cout << t<5>::s(); // {'0',' ','1',' ','2',' ','3',' ','4',' ','5','\0'}
}
And here's a version with "minimal changes":
#include <iostream>
#include <array>
template < unsigned int i, char ... RHS >
struct t {
constexpr static std::array<char, sizeof...(RHS)+2*i+2> s
= t<i-1, ' ', char(i+'0'), RHS...>::s;
};
template < unsigned int i, char ... RHS >
constexpr std::array<char, sizeof...(RHS)+2*i+2> t<i, RHS...>::s;
template <char ... RHS >
struct t<0, RHS...> {
constexpr static std::array<char, sizeof...(RHS)+2> s
= {{'0', RHS..., '\0'}};
};
template <char ... RHS >
constexpr std::array<char, sizeof...(RHS)+2>
t<0, RHS...>::s;
int main() {
std::cout << t<5>::s.data();
}
Note how the array is copied into each class. The most-derived ("top-level") array is odr-used via .data(), so definition of s for the primary template is necessary. The definition of s for the specialization isn't required here.
Instead of using a static data member, you could also construct the array inside a constexpr function:
constexpr static std::array<char, sizeof...(RHS)+2> arr()
{ return {{'0', RHS..., '\0'}}; }
The drawback is that this returned array has automatic lifetime, so you can't pass its .data() to the base classes.
Here is something similar that will create a string. For example, Stringer<7> will create the string "0 1 2 3 4 5 6 7".
template <uint32_t i>
struct Stringer
{
string str = Stringer<i - 1>().str + " " + to_string(i);
};
template <>
struct Stringer<0>
{
string str = "0";
};
int main(int argc, const char *argv[])
{
cout << Stringer<7>().str << endl;
return 0;
}

const char array (c style string) template specialization

I want to be able to specialize based on a constant c style string. The problem is that when I call my templatized function the type is const char[N] where 'N' is the size of the string +1 (null character). How can I specialize for all c-style strings?
The following code displays the problem. You can see the specialization for const char [15] gets matched for "const char [15]" but for "const char[5]" it goes to Generic.
Is there any way to do this?
template <typename T>
struct Test {
static const char* type() { return "Generic"; }
};
template <>
struct Test<const char*> {
static const char* type() { return "const char*"; }
};
template <>
struct Test<const char[]> {
static const char* type() { return "const char[]"; }
};
template <>
struct Test<const char[15]> {
static const char* type() { return "const char[15]"; }
};
template <>
struct Test<char*> {
static const char* type() { return "char*"; }
};
template <>
struct Test<char[]> {
static const char* type() { return "char[]"; }
};
template <typename T>
void PrintType(const T& expected) {
std::cerr << expected << " type " << Test<T>::type() << std::endl;
}
int main(int argc, char* argv[]) {
const char* tmp = "const char*";
PrintType(tmp);
PrintType("const char[]");
PrintType("const char[15]");
PrintType("const char[5]");
}
output when run in Windows 7 - VS 2008
const char* type const char*
const char[] type Generic
const char[15] type const char[15]
const char[5] type Generic
A specialization for any array of chars is:
template< std::size_t N >
struct Test< const char[N] > { ... };
However you can no longer return a char* from type(), unless you write more metafunctions to turn a non-type template parameter into its textual representation.
Try this:
#include <cstdio>
#include <string>
template<class T>
void f2(const T& s) // Handle all kinds of string objects
{ std::printf("string object: %s\n", s.c_str()); }
void f2(const char* s) // Handle const char*
{ std::printf("const char*: %s\n", s); }
// ----------------------------------------------------------------------------
template<size_t N>
void f(const char(&s)[N]) // Handle const char array
{ std::printf("const char[%zu]: %s\n", N, s); }
template<size_t N>
void f(char(&s)[N]) // Handle char array
{ std::printf("char[%zu]: %s\n", N, s); }
template<class T>
inline void f(T&& s) // Handle other cases
{ f2(std::forward<T>(s)); }
int main() {
std::string stringObj = "some kind of string object ...";
char charArr[] = "char array";
const char constCharArr[] = "const char array";
const char* constCharPtr = "const char pointer";
f(stringObj);
f(charArr);
f(constCharArr);
f(constCharPtr);
//f("const char array");
}
Output:
string object: some kind of string object ...
char[11]: char array
const char[17]: const char array
const char*: const char pointer
Explanation
f() has two kinds of overloads: One for char arrays and one for "everything else".
f2() handles the "everything else" case.