title: Pointer to peripheral hardware as template parameter
body: <p>I want to access STM32F0 peripheral register through C++ templates. A GPIO Port is defined as follows by vendor header file:</p>
  
  <p>excerpt stm32f0xx.h</p>
  
  <pre><code>#define     __IO    volatile  //!&lt; Defines 'read / write' permissions             
  
  typedef struct
  {
      __IO uint32_t MODER;        
      __IO uint16_t OTYPER;       
      uint16_t RESERVED0;         
      __IO uint32_t OSPEEDR;      
      __IO uint32_t PUPDR;        
      __IO uint16_t IDR;          
      uint16_t RESERVED1;         
      __IO uint16_t ODR;          
      uint16_t RESERVED2;         
      __IO uint32_t BSRR;         
      __IO uint32_t LCKR;         
      __IO uint32_t AFR[2];       
      __IO uint16_t BRR;          
      uint16_t RESERVED3;         
  } GPIO_TypeDef;
  
  #define PERIPH_BASE           ((uint32_t)0x40000000)
  #define AHB2PERIPH_BASE       (PERIPH_BASE + 0x08000000)
  
  #define GPIOA_BASE            (AHB2PERIPH_BASE + 0x00000000)
  
  #define GPIOA               ((GPIO_TypeDef *) GPIOA_BASE)
  </code></pre>
  
  <p>I created a template class for output handling.</p>
  
  <p>main.cpp:</p>
  
  <pre><code>template &lt;uintptr_t port, uint8_t pin&gt;
  class Output {
  public:
      static void set() {
          GPIO_TypeDef *castedPort = reinterpret_cast&lt;GPIO_TypeDef *&gt;(port);
          castedPort-&gt;ODR = (1 &lt;&lt; pin);
      }
  };
  
  int main(void)
  {
      Output&lt;GPIOA_BASE, 5&gt;::set();
  
      while(1)
      {
      }
  }
  </code></pre>
  
  <p>This code runs fine, if I compile it with launchpad g++ for arm. But I want to test my code
  with GoogleTest, so I made a test for it and tried to compile it.</p>
  
  <p>intArgument.cpp:</p>
  
  <pre><code>#include "gtest/gtest.h"
  
  typedef struct {
      /* see above definition */
  } GPIO_TypeDef;
  
  uint32_t gpioa[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
  
  template &lt;uintptr_t port, int pin&gt;
  class Output {
  public:
    static void set() {
      GPIO_TypeDef * castedPort = reinterpret_cast&lt;GPIO_TypeDef *&gt;(port);
      castedPort-&gt;ODR = (1 &lt;&lt; pin);
    }
  };
  
  TEST(OutputTest, OutputDataRegisterWritten) {
    Output&lt;gpioa, 5&gt;::set();
    GPIO_TypeDef * port = reinterpret_cast&lt;GPIO_TypeDef *&gt;(gpioa);
    EXPECT_EQ((1 &lt;&lt; 5), port-&gt;ODR);
  }
  
  int main(int argc, char **argv) {
    ::testing::InitGoogleTest(&amp;argc, argv);
    return RUN_ALL_TESTS();
  }
  </code></pre>
  
  <p>But now compile fails. A cast to a int via <code>reinterpret_cast</code> is not allowed, because then it is no more a constant expression.</p>
  
  <pre><code>fabian@ubuntu:~/workspace/stackOverflowQuestion$ g++ -std=c++11 intArgument.cpp -lgtest -pthread -o intptrArgument.out
  intArgument.cpp: In member function ‘virtual void OutputTest_OutputDataRegisterWritten_Test::TestBody()’:
  intArgument.cpp:23:18: error: conversion from ‘uint32_t* {aka unsigned int*}’ to ‘long unsigned int’ not considered for non-type template argument
     Output&lt;gpioa, 5&gt;::set();
                    ^
  intArgument.cpp:23:18: error: could not convert template argument ‘gpioa’ to ‘long unsigned int’
  intArgument.cpp:23:26: error: invalid type in declaration before ‘;’ token
      Output&lt;gpioa, 5&gt;::set();
  </code></pre>
  
  <p>So i tried to change type of <code>port</code> to <code>GPIO_TypeDef *</code>.</p>
  
  <p>pointerArgument.cpp:</p>
  
  <pre><code>typedef struct {
      /* see above definition */
  } GPIO_TypeDef;
  
  GPIO_TypeDef gpioa;
  
  // using GPIO_TypeDef * as template argument
  template &lt;GPIO_TypeDef * port, int pin&gt;
  class Output {
  public:
    static void set() {
      port-&gt;ODR = (1 &lt;&lt; pin);
    }
  };
  
  TEST(OutputTest, OutputDataRegisterWritten) {
    Output&lt;&amp;gpioa, 5&gt;::set();
    EXPECT_EQ((1 &lt;&lt; 5), gpioa.ODR);
  }
  
  int main(int argc, char **argv) {
    ::testing::InitGoogleTest(&amp;argc, argv);
    return RUN_ALL_TESTS();
  }
  </code></pre>
  
  <p>It compiled and test is passed.</p>
  
  <pre><code>fabian@ubuntu:~/workspace/stackOverflowQuestion$ g++ -std=c++11 pointerArgument.cpp -lgtest -pthread -o pointerArgument.out
  fabian@ubuntu:~/workspace/stackOverflowQuestion$ ./test.out 
  [==========] Running 1 test from 1 test case.
  [----------] Global test environment set-up.
  [----------] 1 test from OutputTest
  [ RUN      ] OutputTest.OutputDataRegisterWritten
  [       OK ] OutputTest.OutputDataRegisterWritten (0 ms)
  [----------] 1 test from OutputTest (1 ms total)
  
  [----------] Global test environment tear-down
  [==========] 1 test from 1 test case ran. (1 ms total)
  [  PASSED  ] 1 test.
  </code></pre>
  
  <p>But using this approach is failing for the arm compiler:</p>
  
  <p>main.cpp</p>
  
  <pre><code>template &lt;GPIO_TypeDef * port, uint8_t pin&gt;
  class Output {
  public:
      static void set() {
          port-&gt;ODR = (1 &lt;&lt; pin);
      }
  };
  
  int main(void)
  {
      Output&lt;GPIOA, 5&gt;::set();
  
      while(1)
      {
      }
  }
  
  compiler error:
  [cc] main.cpp:13:17: error: '1207959552u' is not a valid template argument for 'GPIO_TypeDef*' because it is not the address of a variable
  [cc] main.cpp:13:25: error: invalid type in declaration before ';' token
  </code></pre>
  
  <p>I understand both errors, but is there any way to get this work? I searched for compiler flags, but did not find
  any, that might change this behaviour. A <code>#define TESTING</code> combined with <code>#ifdef/#ifndef</code> might work, but I dont
  like it, because then tested code differs from produced code. Perhaps there is a nicer solution?</p>
  
  <p>Used Compilers:</p>
  
  <pre><code>g++ (i686-posix-dwarf-rev3, Built by MinGW-W64 project), 4.9-2014q4 by Launchpad for STM32F0XX
  g++ (Ubuntu 4.9.2-0ubuntu1~14.04) 4.9.2 for Testing
  </code></pre>