Linker error for variadic template

廉价感情. 提交于 2019-12-12 12:31:19

问题


I have a program with variadic templates and a helper function:

#include <iostream>
#include <string>

using std::cout;

template<typename... Ts>
void fooImpl(char const *cp, Ts... args);

template<typename... Ts>
inline void foo(const std::string &s, Ts... args)
{
    fooImpl(s.c_str(), args...);
}

void fooImpl(char const *cp)
{
    // do something
}

template<typename T, typename... Ts>
void fooImpl(char const *cp, T val, Ts... args)
{
    char special{'@'};

    while (*cp)
    {
        if (*cp == special)
        {
            // handle val ...

            // recurse over remaining args
            fooImpl(cp, args...);
            return;
        }
        ++cp;
    }    
}

int main()
{
    std::string s = "Hello!";
    foo("Text", s, "C++", 3.14159, 42);
}

This gives a linker error:

/tmp/ccZpPMC2.o:vt-test.cc: function void foo<std::string, char const*, double, int>(std::string const&, std::string, char const*, double, int): error:
undefined reference to 'void fooImpl<std::string, char const*, double, int>(char const*, std::string, char const*, double, int)'

It compiles and links fine if I put the definition of foo down just before main(). So I assume it's just a bug, but I get this with GCC 4.9 and clang 3.5, so maybe I'm missing something?


回答1:


template<typename T, typename... Ts>
void fooImpl(char const *cp, T val, Ts... args) { /* ... */ }

You are declaring an overload (!) of the original template.

Since in the call

fooImpl(s.c_str(), args...);

there is a pack-expansion in the argument list, the unqualified-id denotes a dependent name1. Dependent name resolution applies. [temp.dep.candidate]:

For a function call that depends on a template parameter, the candidate functions are found using the usual lookup rules (3.4.1, 3.4.2, 3.4.3) except that:

  • For the part of the lookup using unqualified name lookup (3.4.1) [..] only function declarations from the template definition context are found.

  • For the part of the lookup using associated namespaces (3.4.2), only function declarations found in either the template definition context or the template instantiation context are found.

It's safe to say that unqualified name lookup won't find the second overload as it solely considers declarations from the definition context of the template.

ADL does apply here, but the global namespace will not be associated with any of the types in the parameter pack. We have std::string, char const*, double, int. [basic.lookup.argdep]/2 specifies:

  • If T is a fundamental type, its associated sets of namespaces and classes are both empty.

  • If T is a class type (including unions), its associated classes are: the class itself; the class of which it is a member, if any; and its direct and indirect base classes. Its associated namespaces are the namespaces of which its associated classes are members. Furthermore, if T is a class template specialization, its associated namespaces and classes also include: the namespaces and classes associated with the types of the template arguments provided for template type parameters (excluding template template parameters); the namespaces of which any template template arguments are members; and the classes of which any member templates used as template template arguments are members.

So neither the fundamental types nor std::string include the global namespace as an associated namespace.

Long story short...

... the global namespace isn't searched in during ADL and the second overload isn't found. Thus the first overload of the function template is the only one found and subsequently chosen by overload resolution. The first overload isn't defined though, hence your linker error is issued.


1) [temp.dep]/1:

In an expression of the form:

      postfix-expression ( expression-listopt)

where the postfix-expression is an id-expression, the id-expression denotes a dependent name if

  • any of the expressions in the expression-list is a pack expansion (14.5.3),
  • [..]


来源:https://stackoverflow.com/questions/27067433/linker-error-for-variadic-template

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!