-1

I'm using gcc 4.8.5 with C++11 and I'm trying to understand if the following behavior is normal or if it is a C++11 limitation / compiler bug.

Basically I get an undefined reference error to a constexpr tuple if I define it inside a class but not if I define it globally.

Following is the complete test code:

// file foo.h
#pragma once
#include <tuple>

struct ObjectStruct
  {
  int a;
  int b;
  };

static constexpr auto g_elements_ = std::make_tuple(
  1,
  2);

struct ObjectInfo
  {
  static constexpr auto elements_ = std::make_tuple(
    1,
    2);
  };

// File tuple_iterator.h
#pragma once
#include <tuple>
template<class Object, class Value, std::size_t I = 0, typename... Tp>
inline typename std::enable_if<I == sizeof...(Tp), void>::type
  iterateT(Object& object, const std::tuple<Tp...>& t, Value value)
  {
  std::cout << "base: " << std::to_string(I) << std::endl;
  }

template<class Object, class Value, std::size_t I = 0, typename... Tp>
inline typename std::enable_if<I < sizeof...(Tp), void>::type
  iterateT(Object& object, const std::tuple<Tp...>& t, Value value)
  {
    std::cout << "N: " << std::to_string(I) << std::endl;
    auto ele = std::get<I>(t);
    // DO something with ele
    iterateT<Object, Value, I + 1, Tp...>(object, t, value);
  }

// file main.cpp
#include <iostream>
#include "foo.h"
#include "tuple_iterator.h"
using namespace std;

int
main ()
{
  ObjectStruct object;
  iterateT (object, ObjectInfo::elements_, 5);
  iterateT (object, g_elements_, 5);

  return 0;
}

I get Error: undefined reference to ObjectInfo::elements_

As I said, no error for the global g_elements_ tuple.

I'd like to create a tuple with make_tuple avoiding the need to specify the arguments to a std::tuple.

Any possible explanation of this behaviour?

svoltron
  • 365
  • 1
  • 10

1 Answers1

3

It's standard C++11 behavior. Even though elements_ is constexpr, it's not a definition. Static member declarations are never definitions prior to C++17. If you ODR-use it (such as by binding it to a reference), there must be an out of class definition.

A simple workaround could be to add this...

constexpr decltype(ObjectInfo::elements_) ObjectInfo::elements_;

... into some source file, build an object and link it.

StoryTeller - Unslander Monica
  • 165,132
  • 21
  • 377
  • 458
  • Damn.. I hoped there was some kind of workaround. PS any resource to learn more about constexpr.. everything I've found about constexpr it's usually at most some pages – svoltron Oct 18 '18 at 07:47
  • any possibility to define it in the cpp without the need to specify the type of the arguments? – svoltron Oct 18 '18 at 07:49
  • As for where to learn, that's not something I have an easy answer to. – StoryTeller - Unslander Monica Oct 18 '18 at 07:50
  • @svoltron https://stackoverflow.com/questions/388242/the-definitive-c-book-guide-and-list is suggested as a place to start learning. I don't know which book is best for constexpr specifically, but many of them cover C++11. – eerorika Oct 18 '18 at 07:57
  • @StoryTeller I've tried what you suggested but I get many other errors like: redeclaration ObjectInfo::elements_ differes in constexpr ... declaration of constexpr bla bla outside of class is not a definition – svoltron Oct 18 '18 at 08:00
  • @svoltron - Not in the header. It's not different than putting `int i;` in a header. You get multiple extern definitions. You want it in a *single* source file. – StoryTeller - Unslander Monica Oct 18 '18 at 08:01
  • @StoryTeller yep I just wrote that line in the .cpp file – svoltron Oct 18 '18 at 08:09
  • 1
    @svoltron - I can't really help you more beyond what I did. [It works on GCC 4.8.5 here](https://wandbox.org/permlink/hdKI29llRpfDB7LZ). – StoryTeller - Unslander Monica Oct 18 '18 at 08:11
  • @StoryTeller it works if I build an object like: decltype(ObjectInfo4::elements_) t; and pass it to the iterateT function. It seems there is no need to write that line in the cpp file though – svoltron Oct 18 '18 at 08:11
  • 1
    @svoltron - But then you don't pass `elements_` itself. In which case, I don't see why bother with the object at all. – StoryTeller - Unslander Monica Oct 18 '18 at 08:12
  • @StoryTeller that's totally true of course. Please check here https://wandbox.org/permlink/SZ5Pn7dPB440fYnI I've just added it in the .cpp file. I have also tried other ways but still no success – svoltron Oct 18 '18 at 08:25
  • 1
    @svoltron - You have something fishy in the build process on your end. As for wandbox, the command line doesn't build and link `a.cpp` either (note `a.cpp` is not in the command line). Case and point: putting the the definition in `prog.cc` build successfully https://wandbox.org/permlink/0HWjdAqzEJSKtxYX . – StoryTeller - Unslander Monica Oct 18 '18 at 08:33
  • I've tried with my compiler in my machine and indeed it works. Thank you again for everything. – svoltron Oct 18 '18 at 08:35