4

I know why I can't use float as template parameter and how to set a static const float member of template class thanks to a numerator/denominator couple. But I was trying another "hack" based on reinterpret_cast to "emule" float template parameters from its IEEE754 hexadecimal writing.

Here is the small piece of code :

#include <iostream>
#include <cstdint>

template <uint32_t T>
struct MyStruct
{
    static const float value;
};

template <uint32_t T>
const float MyStruct<T>::value = *reinterpret_cast<float*>(T);

int main()
{
    typedef MyStruct<0x40490fdb> Test;
    std::cout << Test::value << std::endl;
    return 0;
}

I compile it...

g++ -Wall -pedantic main.cpp -std=c++0x -g

with no warnings.

And it segfaulted...

brugelca@artemis:~/workspace/draft$ ./a.out 
Segmentation fault (core dumped)

Here is the valgrind output :

brugelca@artemis:~/workspace/draft$ valgrind ./a.out
==10871== Memcheck, a memory error detector
==10871== Copyright (C) 2002-2012, and GNU GPL'd, by Julian Seward et al.
==10871== Using Valgrind-3.8.1 and LibVEX; rerun with -h for copyright info
==10871== Command: ./a.out
==10871== 
==10871== Invalid read of size 4
==10871==    at 0x4008B5: __static_initialization_and_destruction_0(int, int) (main.cpp:11)
==10871==    by 0x4008D1: _GLOBAL__sub_I_main (main.cpp:18)
==10871==    by 0x40093C: __libc_csu_init (in /home/brugelca/workspace/draft/a.out)
==10871==    by 0x5159D74: (below main) (libc-start.c:219)
==10871==  Address 0x40490fdb is not stack'd, malloc'd or (recently) free'd
==10871== 
==10871== 
==10871== Process terminating with default action of signal 11 (SIGSEGV)
==10871==  Access not within mapped region at address 0x40490FDB
==10871==    at 0x4008B5: __static_initialization_and_destruction_0(int, int) (main.cpp:11)
==10871==    by 0x4008D1: _GLOBAL__sub_I_main (main.cpp:18)
==10871==    by 0x40093C: __libc_csu_init (in /home/brugelca/workspace/draft/a.out)
==10871==    by 0x5159D74: (below main) (libc-start.c:219)
==10871==  If you believe this happened as a result of a stack
==10871==  overflow in your program's main thread (unlikely but
==10871==  possible), you can try to increase the size of the
==10871==  main thread stack using the --main-stacksize= flag.
==10871==  The main thread stack size used in this run was 8388608.
==10871== 
==10871== HEAP SUMMARY:
==10871==     in use at exit: 0 bytes in 0 blocks
==10871==   total heap usage: 0 allocs, 0 frees, 0 bytes allocated
==10871== 
==10871== All heap blocks were freed -- no leaks are possible
==10871== 
==10871== For counts of detected and suppressed errors, rerun with: -v
==10871== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 2 from 2)

Should this code compile ? (I was a bit surprised that both clang and g++ allow the reinterpret_cast) Why does it segfaulted ? How to achieve what I wanted in the first place ?

Community
  • 1
  • 1
matovitch
  • 1,264
  • 11
  • 26

2 Answers2

7

Your code reinterprets 0x40490fdb as a pointer to float, not as the hex value of a float. Hence the segfault.

Try the following:

constexpr float uint32_to_float(uint32_t val) {
  return *reinterpret_cast<float*>(&val);
}

template <uint32_t T>
const float MyStruct<T>::value = uint32_to_float(T);
NPE
  • 486,780
  • 108
  • 951
  • 1,012
  • @matovitch: See the updated answer with a proposed workaround. – NPE Apr 07 '14 at 20:07
  • I think I will delete this question. First because I am ashamed of it and second because I don't think this will be useful to anyone else. – matovitch Apr 07 '14 at 20:08
  • And without constexpr (I think it's c++11) ? – matovitch Apr 07 '14 at 20:08
  • @matovitch: You are of course free to delete any of your questions. Doing so is, however, disrespectful towards those who have made the effort to try and help you. – NPE Apr 07 '14 at 20:09
  • You lose the reputation points you gained ? Anyway since you edited your answer this could be useful to someone so I will keep it. – matovitch Apr 07 '14 at 20:11
  • 1
    @matovitch: It's not about the points, but about respecting each other's time. BTW, the community does a pretty good job of swiftly closing unsuitable questions, and so far not a single close vote has been cast. – NPE Apr 07 '14 at 20:18
  • @NPE The advices my parents gave me have already vanished but your answer will stay. Am I being disrespectful ? The web has to settle for a little mortality. – matovitch Apr 07 '14 at 20:42
  • @CantChooseUsernames Unfortunately, not all floats could be represented in such way (ratio of integer numbers, even `int64_t` numbers). – Constructor Apr 07 '14 at 21:23
  • @NPE (bis) My last comment looks bitter afterwards (which wasn't its spirit at all :-)). I just would say for example that the advices you gave orally disappeared but aren't necessary a waste of time. And the fact there wasn't a clerk to record all your words doesn't make the listening less respectful IMHO. – matovitch Apr 07 '14 at 22:19
  • A slight improvement to this would be to cut down on the amount of asterisks by using the reference version of `reinterpret_cast` as such: `reinterpret_cast(val)` – Agentlien Apr 08 '14 at 07:44
1

The segfault in the question was a vulgar mistake but the question remains. How to pass a float in ieee754 format as a template argument ?

The C++11 way

This solution was given by NPE (modified but not tested) :

#include <iostream>
#include <cstdint>

template <uint32_t T>
struct MyStruct
{
    static const float value;
}; 

constexpr float uint32_to_float(uint32_t val) {
    return reinterpret_cast<float&>(val);
}

template <uint32_t T>
const float MyStruct<T>::value = uint32_to_float(T);

int main()
{
    const uint32_t pi = 0x40490fdb;
    std::cout << MyStruct<pi>::value << std::endl;
}

The old fashioned way

Relativly small, I'm proud of it ! :-)

#include <iostream>
#include <stdio.h>

template <uint32_t T>
union MyStruct
{
    static const uint32_t int_val = T;
    static const float    flt_val;
};

template <uint32_t T>
const float MyStruct<T>::flt_val = reinterpret_cast<const float&>(MyStruct<T>::int_val);

int main()
{
    const uint32_t pi = 0x40490fdb;
    std::cout << MyStruct<pi>::flt_val << std::endl;
    return 0;
}
matovitch
  • 1,264
  • 11
  • 26