单个模板实例化用于单独的对象

Vyt*_*ius 2 c++ templates

考虑以下:

/* T.h */
template <class T>
void Too() {
    std::cout << "  Template: " << typeid(T).name()
              << " size: " << sizeof(T) << std::endl;
}
Run Code Online (Sandbox Code Playgroud)
/* A.h */
extern void FooA();
Run Code Online (Sandbox Code Playgroud)
/* A.cpp */
struct Local {
    int a[2];
}

void FooA() {
    Local l;
    std::cout << "<Foo A>:\n" << "  Real: " << typeid(l).name()
              << " size: " << sizeof(l) << std::endl;
    Too<Local>();
}
Run Code Online (Sandbox Code Playgroud)
/* B.h */
extern void FooB();
Run Code Online (Sandbox Code Playgroud)
/* B.cpp */
struct Local {
    int a[4];
};

void FooB() {
    Local l;
    std::cout << "<Foo B>:\n" << "  Real: " << typeid(l).name() \
              << " size: " << sizeof(l) << std::endl;
    Too<Local>();
}
Run Code Online (Sandbox Code Playgroud)
/* main.cpp */
int main() {
    FooA();
    FooB();
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

编译和运行结果:

<Foo A>:
  Real: 5Local size: 8
  Template: 5Local size: 8
<Foo B>:
  Real: 5Local size: 16
  Template: 5Local size: 8
Run Code Online (Sandbox Code Playgroud)

这意味着单个模板实例化用于两个模板调用.值得注意的是 - 第一个.虽然可以通过定义Too()as 来解决此"功能"

template <class T, size_t s = sizeof(T)> Too();
Run Code Online (Sandbox Code Playgroud)

我想知道这个问题还有更通用的方法吗?如果两个调用结构具有相同的大小,则上述代码仍将失败.

编辑:

具体来说,我的问题在于,我无法更改文件A和B.所以我可能不会向他们引入匿名命名空间.有没有模板边解决方案?因此第二个模板参数.

Rei*_*ica 7

您的程序通过包含两个定义来违反ODR(一个定义规则)struct Local.这意味着它形成不良并且具有未定义的行为,因此任何事情都可能发生.

  • 你已经表明了什么是错的,但没有回答问题/提供了解决方案...... (2认同)
  • @vytis该标准不要求编译器检测ODR违规; 原因是在传统的设置中,*编译器*只知道单个翻译单元,*链接器*不知道结构. (2认同)

wol*_*ang 6

正如已经指出的那样,您违反了一个定义规则.

您可以在匿名命名空间中定义本地结构,以便编译器知道您正在讨论不同的本地类型,然后一切都应该"工作":

/* A.cpp */
namespace {
    struct Local {
        int a[2];
    }
}

/* B.cpp */
namespace {
    struct Local {
        int a[4];
    }
}
Run Code Online (Sandbox Code Playgroud)