0

So in my C++11 project, I'm trying to alias a specific traits template specialisation based on a class template parameter. This is intended so that I can inherit from the template, using CRTP, and access the members of the traits template without needing to refer to the type used to specialise it.

improved minimal example:

main.cpp

#include "Matrix.h"
#include "MatrixImplementation.h"

int main()
{
    HAL_Matrix<NXP_HAL_Matrix>().Scan();
    return 0;
}

Matrix.h

#pragma once
#include <array>

template <uint8_t ... Pins>
static constexpr std::array<uint8_t, sizeof...(Pins)> MakePinArray()
{
    return (std::array<uint8_t, sizeof...(Pins)> { { Pins... } });
};


template <class HAL_Matrix_Implementation>
struct MatrixTraits
{

};

template <>
struct MatrixTraits<class HAL_Matrix_Implementation>
{};


template <class HAL_Matrix_Implementation>
class HAL_Matrix
{
public:
    using MatrixParameters = ::template MatrixTraits<HAL_Matrix_Implementation>;
    void Scan()
    {
        auto test = MatrixParameters::RowPins;
        auto test2 = MatrixParameters::ColumnPins;
    };
};

MatrixImplementation.h

#pragma once

#include "Matrix.h"
#include <array>
#include <stdint-gcc.h>



class NXP_HAL_Matrix : public HAL_Matrix<NXP_HAL_Matrix>
{
public:

    void Scan() {};
    void Initialize() {};
};


template <>
struct MatrixTraits<NXP_HAL_Matrix>
{
public:
    static constexpr auto RowPins = MakePinArray<1,2,3>();
    static constexpr auto ColumnPins = 3;
};

At compile-time I get the following error:

Debug/main.o: In function `HAL_Matrix<NXP_HAL_Matrix>::Scan()':
<path>\Matrix.h(31): error VGDB1000: undefined reference to `MatrixTraits<NXP_HAL_Matrix>::RowPins'

While preparing this minimal example it became apparent to me that my attempt to access RowPins gives an undefined reference, but storing just an int in ColumnPins means I can access it without error. As a result I'm presuming that there's something wrong with my MakePinArray template function so that the compiler is ignoring the constexpr specifier, and allowing it to be called at runtime hence the undefined reference error.

However, I've looked at other answers such as the second suggestion in this answer: Create N-element constexpr array in C++11 and can't detect a functional difference between his build_array function and mine.

Can anybody a) confirm that my understanding is correct (ie that constexpr specifier is being discarded, causing there to be a declaration for RowPins but no definition) and b) suggest how I rectify this?

Just for further information if it is helpful, I'm using VisualGDB/arm-gcc 4.9.2 and compiling with -std=c++11 .

Community
  • 1
  • 1
Ishamael
  • 1
  • 3
  • Is that the *only* error you get? You seem to be missing e.g. a `struct` keyword in the code you show. Please try to create a [Minimal, Complete, and Verifiable Example](http://stackoverflow.com/help/mcve) and show us, together with the complete and unedited error output. – Some programmer dude Aug 06 '15 at 04:28
  • "Undefined reference" often means you are violating the ODR by not providing a definition. – T.C. Aug 06 '15 at 05:07
  • @JoachimPileborg - you're right, I was writing out a sample based on my actual project but made an error. I'll update with a MCVE as soon as possible. – Ishamael Aug 06 '15 at 05:20
  • @T.C. - does `static constexpr auto Array1 = MakeConstArray<1,2,3>();` not constitute a definition because it is a static constant? I did consider the possibility you mention, but from my existing research I believe that it does. – Ishamael Aug 06 '15 at 05:22
  • @JoachimPileborg Updated the question and minimal example. Thanks. – Ishamael Aug 06 '15 at 09:30
  • @Ishamael Your program now compiles and links for me with the stock ubuntu 14.04 gcc 4.9.2, std=c++11. The only diagnostics are for the unused variables `test` and `test2` in the `Scan` method. Likewise with gcc 5.1 and clang 3.6. The problem appears to lie with your VisualGDB toolchain. – Mike Kinghan Aug 06 '15 at 11:27
  • @MikeKinghan I've tried both the latest official precompiled 4.9.2 arm-gcc binaries, as well as a bleeding-edge unofficial 4.9.3 release and they exhibit the same behaviour. Perhaps its an issue with the fact I'm targeting ARM? Guess I'll need to go ask some questions on the gcc-arm-embedded launchpad page. Thanks for the assistance. – Ishamael Aug 07 '15 at 07:34
  • No, an in-class static data member declaration is never a definition, constant or not. For constants you are sometimes allowed to use it anyway, without a definition, but the exact rules can be somewhat tricky. – T.C. Aug 08 '15 at 05:06
  • @T.C. Are you referring to the one-definition rule? If so, does the std::array not satisfy the requirements for appearing in a constant expression as per the standard, given that it's convertable to an array of literal-type? I'm referring to : _A variable whose name appears as a potentially-evaluated expression is odr-used unless it is an object that satisfies the requirements for appearing in a constant expression (5.19) and the lvalue-to-rvalue conversion (4.1) is immediately applied._ – Ishamael Aug 08 '15 at 12:38

0 Answers0