samedi 1 août 2015

Inline function is not defined

Using Variant and Visitor idioms for dealing with abstract syntax tree of mathematical expression I faced linker errors undefined reference to 'function_name' prepended with warnings inline function 'function_name' is not defined [-Wundefined-inline], where function_name is all possible names of specializations (i.e. for B and for C) of function marked // 1 below (header):

#pragma once
#include <utility>
#include <iostream>

#include <boost/variant.hpp>

struct A {};
struct B {};
struct C {};

using V = boost::variant< A, B, C >;

struct visitor
{

    using result_type = void;

    result_type
    operator () (V v) const
    {
#if 1
        return boost::apply_visitor([this] (auto && x) -> result_type { return apply(std::forward< decltype(x) >(x)); }, v);
    }
#else
        return boost::apply_visitor(*this, v);
    }

    template< typename T >
    result_type
    operator () (T && x) const
    {
        return apply(std::forward< T >(x));
    }
#endif

private :

    result_type
    apply(A) const
    {
        std::cout << __PRETTY_FUNCTION__ << std::endl;
    }

    template< typename T >
    result_type
    apply(T &&) const
    {
        std::cout << __PRETTY_FUNCTION__ << std::endl;
    }

public : // !

};

(main.cpp):

#include "implementation.hpp"

#include <cstdlib>

int
main()
{
    visitor{}(V{B{}});
    return EXIT_SUCCESS;
}

Here is live example: main.cpp and header files. If contents of header file moved to main.cpp, then warning changed to function 'function_name' has internal linkage but is not defined [-Wundefined-internal]. But I am sure the sources of errors are exactly the same.

If I change #if 0 to #if 1, then all compiles fine. Another note is: when I move result_type operator () (V v) const to second public section (marked // !), then all compiles fine too.

Seems lambda makes something subtle with instantiation of function template defined strictly below definition of lambda.

How to explain above behaviour and difference in behaviour of lambda version and version with visitor & passed to boost::apply_visitor?

Real-life example is here.

Aucun commentaire:

Enregistrer un commentaire