这在 C++ 中可以合法地完成吗?

发布于 2024-11-05 11:34:50 字数 1116 浏览 0 评论 0原文

注意:以下代码非法 ,但符合标准的编译器不需要拒绝它(有些编译器不需要)。

在我正在使用的库中,我有一个 Foo 的模板函数声明以及 foobar.hBar 的模板函数定义:

template<class C> int Foo();

template<class C> int Bar() {
  return Something(  Foo<C>()  );
}

其目的是其他代码能够像这样使用它:

#include "foobar.h"

int main() {
  Bar<MyClass>();
  return 0;
}

// Ideally, the usage (above) and the definition (below)
// would/could be in different translation units. 

template<> int Foo<MyClass>() { return 5; }

问题: 有没有办法让这项工作也合法?


问题是(如果我理解正确的话)尽管编译了,但这在技术上是非法的:它违反了 ODR 因为显式专业化和 Bar 的使用都算作定义,尽管事实上,在用例中没有可以使用的主体。

我想使用此模式来参数化 Foo 的原因是,作为我需要遵循的样式指南的结果,确保在 < 定义之前按词法包含任何内容的唯一方法code>Bar 用于将其包含在 foobar.h 中。但是(因为我希望我不需要解释的原因)这是不可能的。

Note: the following code is illegal, but a conforming compiler is not required to reject it (and some don't).

In a library I'm working with I have a template function declaration for Foo and a template function definition for Bar in foobar.h:

template<class C> int Foo();

template<class C> int Bar() {
  return Something(  Foo<C>()  );
}

The intent is that other code would be able to use it like this:

#include "foobar.h"

int main() {
  Bar<MyClass>();
  return 0;
}

// Ideally, the usage (above) and the definition (below)
// would/could be in different translation units. 

template<> int Foo<MyClass>() { return 5; }

The question: Is there a way to make this work that is also legal?


The issue is (if I'm understanding things correctly) that despite compiling, this is technically illegal: it violates the ODR because both the explicit specialization and the usage of Bar<MyClass> count as definitions, despite the fact that there is no body to work with in the usage case.

The reasons I want to use this pattern to parameterize Foo is that, as a result of the style guide I'm required to follow, the only way to ensure that anything is lexically included before the definition of Bar is for it to be included by foobar.h. But (for reason I expect I don't need to explain) that's a non-starter.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

小傻瓜 2024-11-12 11:34:50

有没有办法让这项工作也合法?

是的,在使用之前声明专业化。只需交换文件中专业化和主要的顺序即可在您提供的示例中执行此操作。但是,在示例中,您仍然必须确保没有其他 TU 在未声明的情况下使用该专业化。

一般来说,这些专业化应该在标头中声明。

在您的示例的范围内(即没有根本性的改变),没有其他方法可以完成这项工作。

Is there a way to make this work that is also legal?

Yes, declare the specialization before it is used. Simply swapping the order of the specialization and main in your file would do this in the example you provided. However, in the example, you would still have to make sure no other TU used the specialization without declaring it.

Generally these specializations should be declared in a header.

Within what appear to be the confines of your example (i.e. no radical changes), there is no other way to make this work.

浅浅 2024-11-12 11:34:50

这是不合法的,因为不可能专门化模板函数。

你可以这样做:

template< typename T >
struct foo
{
  static int doSomething() {return 0;}
};
template< >
struct foo<int>
{
  static int doSomething() {return 5;}
};

It is not legal, since it is not possible to specialize template functions.

You could do something like this :

template< typename T >
struct foo
{
  static int doSomething() {return 0;}
};
template< >
struct foo<int>
{
  static int doSomething() {return 5;}
};
月亮邮递员 2024-11-12 11:34:50

这会编译链接并在 VS2008 和 gcc 4.5.2 上运行:

template<class C> int Foo();

int Something(int i ){ return i; }

template<class C> int Bar() {
    return Something(  Foo<C>()  );
}

class MyClass{};
class FooClass{};

// Update:
// Declaration of a specialisation.
template<> int Foo<MyClass>();

int Zoo(){
    return Something(  Foo<MyClass>()  );
}

#include <iostream>

int main() {
    std::cout << Bar<MyClass>() << std::endl;
    std::cout << Zoo() << std::endl;
    std::cout << Bar<FooClass>() << std::endl;
    return 0;
}

// Definitions of specialisations.
template<> int Foo<MyClass>() { return 5; }
template<> int Foo<FooClass>() { return 6; }

输出为:

5
5
6

其工作原理是,尽管仅声明了模板函数 Foo ,但它确实具有两个必需的定义,可用于链接器。
在编译时,当编译器看到 main 的定义时,它可以创建 Bar 的特化,但无法创建 Foo 的特化。在本例中,它只是创建对 Foo()Foo() 的函数调用。
随后,编译器发现它编译的 Foo 的特化,并将其保留在目标文件中,但当时不执行任何其他操作。当链接器运行时,它会找到它需要的一切。

更新:
所以我不知道为什么这是非法的,但由于某种原因它似乎可以编译并运行。

This compiles links and runs with both VS2008 and gcc 4.5.2:

template<class C> int Foo();

int Something(int i ){ return i; }

template<class C> int Bar() {
    return Something(  Foo<C>()  );
}

class MyClass{};
class FooClass{};

// Update:
// Declaration of a specialisation.
template<> int Foo<MyClass>();

int Zoo(){
    return Something(  Foo<MyClass>()  );
}

#include <iostream>

int main() {
    std::cout << Bar<MyClass>() << std::endl;
    std::cout << Zoo() << std::endl;
    std::cout << Bar<FooClass>() << std::endl;
    return 0;
}

// Definitions of specialisations.
template<> int Foo<MyClass>() { return 5; }
template<> int Foo<FooClass>() { return 6; }

The output is:

5
5
6

The reason this works is that despite only being declared, template function Foo does have the two required definitions available to the linker.
At compile time, when the compiler sees the definition of main, it can create specialisations of Bar, but cannot create specialisations of Foo. In this case it just creates function calls to Foo<MyClass>() and Foo<FooClass>().
Later on the compiler finds specialisations of Foo which it compiles, leaves in the object file, but does nothing else with at the time. When the linker runs it finds everything it needs.

Update:
So I don't know why this is illegal, but for some reason it does seems to compile and run.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文