首页 > 解决方案 > 为什么在匿名命名空间中定义模板时出现内部链接错误?

问题描述

在匿名命名空间中声明模板会导致错误error: function '(anonymous namespace)::f<std::__1::vector<float, std::__1::allocator<float> > >' has internal linkage but is not defined

代码如下:

    #include <type_traits>
    #include <vector>

    namespace {

    template <class T>
    void f(const T& data);

    template <>
    void f<int>(const int& data){}

    template <typename Iterable, typename std::decay<decltype(*std::begin(std::declval<Iterable>()))>::type>
    void f(const Iterable& data) {
        ;
    }

    }

    void g() {
        std::vector<float> x;
        f(x);
    }

我搜索并找到了可能相同,但它不会解释。

更新:
如果我删除匿名命名空间,错误会变成Undefined symbols for void f<std::__1::vector<float, std::__1::allocator<float> > >(std::__1::vector<float, std::__1::allocator<float> > const&.

标签: c++templateslinkertemplate-specialization

解决方案


你有两个重载的模板函数f,第二个有两个模板参数。f(x);将调用void f(const T& data);确实没有在任何地方定义的。

我现在将勾勒出一个简短的解决方案。

最实用的方法是使用部分特化的辅助类,因为模板函数不能部分特化。

#include <type_traits>
#include <vector>
#include <iostream>

namespace {

    template<typename T, typename=void>
    struct ff;

    template<>
    struct ff<int, void> {

        static constexpr bool specialized=true;
        static inline void func(const int &data)
        {
            std::cout << "int" << std::endl;
        }
    };

    template<typename T>
    struct ff<T,
         std::void_t<decltype(*std::begin(std::declval<T>()))>> {

        static constexpr bool specialized=true;
        static inline void func(const T &data)
        {
            std::cout << "vector" << std::endl;
        }
    };

    template <class T, typename=decltype(ff<T>::specialized)>
    inline void f(const T& data)
    {
        ff<T>::func(data);
    }
}

int main()
{
    std::vector<float> x;
    int y;
    f(x); // Result: vector
    f(y); // Result: int

    // Error:
    //
    // char *z;
    // f(z);
}

出于 SFINAE 的目的,您仍然需要模板函数上的第二个模板参数,并且大多数编译器应该在中等优化级别上优化掉额外的函数调用。


推荐阅读