I play with the constexpr keyword and encoded the following simple program:
#include <iostream>
using namespace std;
template<typename T>
constexpr bool is_equal(T const* array1, T const* array2, size_t len)
{
return array1 == array2 || (len ? array1[len - 1] == array2[len - 1] && is_equal<T>(array1, array2, len - 1) : true);
}
template<typename T, size_t N1, size_t N2>
constexpr bool is_equal(T const (&array1)[N1], T const (&array2)[N2])
{
return N1 == N2 && is_equal<T>(array1, array2, N1);
}
template<typename T, size_t N>
constexpr size_t arraylength(T const (&array)[N])
{
return N;
}
constexpr size_t stringlength(char const* str, size_t len=0)
{
return str ? (*str ? stringlength(str + 1, len + 1) : len) : 0;
}
constexpr size_t min(size_t one, size_t another)
{
return one < another ? one : another;
}
constexpr size_t min_length(char const* str1, char const* str2)
{
return min(stringlength(str1), stringlength(str2));
}
template<typename T, size_t N1, size_t N2>
constexpr size_t min_length(T const (&array1)[N1], T const (&array2)[N2])
{
return min(N1, N2);
}
template<bool cond=false>
struct to_num
{
enum {value=0};
};
template<>
struct to_num<true>
{
enum {value=42};
};
template<size_t init>
struct two_times
{
enum {value=init*2};
};
static constexpr char x[]{"One string"};
static constexpr char y[]{"One string"};
static constexpr int a[]{1,2,3,4};
static constexpr int b[]{1,2,3,4};
static constexpr int const* const c = &a[0];
static constexpr int const* const d = &b[0];
int main()
{
cout << "The two literals are equal: " << to_num< is_equal("One string", "One string") >::value << endl;
cout << "The two variables x & y are equal: " << to_num< is_equal(x, y) >::value << endl;
cout << "Pointers a & c are equal: " << to_num< a == c >::value << endl;
cout << "Pointers b & c are equal: " << to_num< b == c >::value << endl;
cout << "Pointers c & d are equal: " << to_num< c == d >::value << endl;
cout << "The contents of c & d is the same: " << to_num< is_equal(c, d, arraylength(a)) >::value << endl;
cout << "Pointers a & b are equal: " << to_num< a == b >::value << endl;
cout << "The contents of a & b is the same: " << to_num< is_equal(a, b) >::value << endl;
cout << "String x contains " << two_times< stringlength(x) >::value / 2 << " characters" << endl;
cout << "String literal contains " << two_times< stringlength("literal") >::value / 2 << " characters" << endl;
cout << "Array literal contains " << two_times< arraylength("literal") >::value / 2 << " values" << endl;
return 0;
}
As a comment comment, some code compiles and works fine with g ++, but not with clang ++ and other compilers and works fine with clang ++, but not with g ++
Gcc error:
comaprison.cpp: In function ‘int main()’:
comaprison.cpp:97:62: in constexpr expansion of ‘stringlength(((const char*)(& x)), 0ul)’
comaprison.cpp:29:55: in constexpr expansion of ‘stringlength((str + 1u), (len + 1ul))’
comaprison.cpp:97:64: error: ‘((((const char*)(& x)) + 1u) != 0u)’ is not a constant expression
cout << "String x contains " << two_times< stringlength(x) >::value / 2 << " characters" << endl;
^
comaprison.cpp:97:64: note: in template argument for type ‘long unsigned int’
comaprison.cpp:98:76: in constexpr expansion of ‘stringlength(((const char*)"literal"), 0ul)’
comaprison.cpp:29:55: in constexpr expansion of ‘stringlength((str + 1u), (len + 1ul))’
comaprison.cpp:98:78: error: ‘((((const char*)"literal") + 1u) != 0u)’ is not a constant expression
cout << "String literal contains " << two_times< stringlength("literal") >::value / 2 << " characters" << endl;
^
comaprison.cpp:98:78: note: in template argument for type ‘long unsigned int’
and clang ++ one:
comaprison.cpp:89:55: error: non-type template argument is not a constant expression
cout << "The two literals are equal: " << to_num< is_equal("One string", "One string") >::value << ...
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
comaprison.cpp:8:19: note: subexpression not valid in a constant expression
return array1 == array2 || (len ? array1[len - 1] == array2[len - 1] && is_equal<T>(array1, array2...
^
comaprison.cpp:14:24: note: in call to 'is_equal(&"One string"[0], &"One string"[0], 11)'
return N1 == N2 && is_equal<T>(array1, array2, N1);
^
comaprison.cpp:89:55: note: in call to 'is_equal("One string", "One string")'
cout << "The two literals are equal: " << to_num< is_equal("One string", "One string") >::value << ...
^
1 error generated.
g ++ - "gcc version 4.8.1 (Ubuntu / Linaro 4.8.1-10ubuntu9)", clang ++ - "Ubuntu clang version 3.4-1ubuntu1 (trunk) (based on LLVM 3.4)"
Both on Linux x86_64.
Command lines:
clang++ -std=c++11 -o comaprison comaprison.cpp
g++ -std=c++11 -o comaprison comaprison.cpp
So, am I doing something outside the C ++ 11 standard with this code, or is something wrong with both compilers?
: g++, clang++, g++, clang++ g++, clang++
, , .
.