Question

I have the following code:

struct Port {
    int reg1;
    int reg2;
};

#define PORT1 ((Port *) 0x00010000); // absolutely compile-time constants
#define PORT2 ((Port *) 0x00020000);

template <Port * port>
class PortWrapper {
public:
    PortWrapper() {
        port->reg1 = 1;
        port->reg2 = 2;
    }
};

constexpr static const Port * const port1c = PORT1;

int main(int argc, char* argv[]) {
    PortWrapper<PORT1> port1; //Compiler says: error: could not convert template argument '65536u' to 'Port*'
    PortWrapper<port1c> port1; //Compiler says: error: 'port1c' is not a valid template argument because 'port1c' is a variable, not the address of a variable 
}

How can I instantiate this template?

I can do this:

Port port;
int main() {
    PortWrapper<&port> port1;
}

But that's not what I need. I need port to be mapped to predefined constant address.

Was it helpful?

Solution

You can't as-is, because non-type template arguments of pointer type can only be null pointer expressions or addresses of objects, and a conversion from an integer is neither of those.

You could redesign the template slightly:

template <uintptr_t portAddr>
class PortWrapper {
private:
  static constexpr Port* port() { return (Port*)portAddr; }

public:
  PortWrapper() {
    port()->reg1 = 1;
    port()->reg2 = 2;
  }
};

Note that in the comments, @KonradRudolph disputes whether this strictly follows the rules for a constexpr function, and it's quite possible it does not. Nevertheless, even if constexpr is omitted from the above, any decent compiler will inline the call of port(), effectively resulting in compile-time evaluation.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top