Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

integral_constant vs constexpr

Could you please explain, why integral_constant and constexpr approaches in the following example result in different behaviours?

#include <iostream>

using namespace std;

struct Logger
{
//    template<typename Type>
//    using IsRawString =
//        std::integral_constant<bool, std::is_same<const char*, Type>::value || std::is_same<char*, Type>::value>;

    template<typename Type>
    constexpr bool IsRawString()
    {
        return std::is_same<const char*, Type>::value || std::is_same<char*, Type>::value;
    }

    template<typename Type, typename Enable = void>
    struct Traits
    {
        static const int Index = 1;
    };

    template<typename Type>
    struct Traits<Type, std::enable_if_t<IsRawString<Type>()>>
    {
        static const int Index = 2;
    };

    template<typename Type>
    struct Traits<Type, std::enable_if_t<std::is_pointer<Type>::value && !IsRawString<Type>()>>
    {
        static const int Index = 3;
    };

};

int main()
{
    cout << Logger::Traits<int>::Index << endl
         << Logger::Traits<char*>::Index << endl
         << Logger::Traits<const char*>::Index << endl
         << Logger::Traits<void*>::Index << endl;


    return 0;
}

integral_constant approach https://ideone.com/WQy71r:

1
2
2
3

constexpr approach https://ideone.com/wPiM1m:

1
1
1
1

If I remove Logger struct and use Traits from the global scope, both approaches give the same result as for integral_constant inside struct (https://ideone.com/WGVuXE https://ideone.com/OpTbDm).

like image 936
NuPagadi Avatar asked Oct 09 '17 16:10

NuPagadi


People also ask

What is the difference between constexpr and constexpr?

Unlike const, constexpr can also be applied to functions and class constructors. constexpr indicates that the value, or return value, is constant and, where possible, is computed at compile time. A constexpr integral value can be used wherever a const integer is required, such as in template arguments and array declarations.

What is the use of a const integral in C++?

A constexpr integral value can be used wherever a const integer is required, such as in template arguments and array declarations. And when a value can be computed at compile time instead of run time, it can help your program run faster and use less memory.

When does a constexpr function produce a compile-time constant?

When its arguments are constexpr values, a constexpr function produces a compile-time constant. When called with non- constexpr arguments, or when its value isn't required at compile time, it produces a value at run time like a regular function.

What is the difference between const int and const int *?

TL;DR: const applies to the thing left of it, if there's nothing on the left, then it applies to the thing right of it const int *: nothing on the left, so const if for int: a pointer to a constant integer. equivalent to int const *


1 Answers

It happens because your IsRawString() declared as non static and it require class object for to be called.

When compiler try to generate Logger::Traits<char*>::Index and Logger::Traits<const char*>::Index it use SFINAE(http://en.cppreference.com/w/cpp/language/sfinae) and reject wrong variants with your constexpr function. The first Traits form with template<typename Type, typename Enable = void> generates only. Try declare IsRawString() as static member function

like image 174
Sergey_Ivanov Avatar answered Oct 21 '22 08:10

Sergey_Ivanov