Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/templates/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 这是否可以合法地用C++;?_C++_Templates_Language Specifications_One Definition Rule - Fatal编程技术网

C++ 这是否可以合法地用C++;?

C++ 这是否可以合法地用C++;?,c++,templates,language-specifications,one-definition-rule,C++,Templates,Language Specifications,One Definition Rule,注:(有些没有) 在我正在使用的库中,我有一个Foo的模板函数声明和foobar.h中的Bar的模板函数定义: template<class C> int Foo(); template<class C> int Bar() { return Something( Foo<C>() ); } template int Foo(); 模板整型条(){ 返回某物(Foo()); } 其目的是其他代码可以像这样使用它: #include "foobar

注:(有些没有)

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

template<class C> int Foo();

template<class C> int Bar() {
  return Something(  Foo<C>()  );
}
template int Foo();
模板整型条(){
返回某物(Foo());
}
其目的是其他代码可以像这样使用它:

#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; }
#包括“foobar.h”
int main(){
Bar();
返回0;
}
//理想情况下,用法(上面)和定义(下面)
//将/可能在不同的翻译单位。
模板int Foo(){return 5;}

问题是:有没有办法使这项工作合法化


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


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

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

你可以这样做:

template< typename T >
struct foo
{
  static int doSomething() {return 0;}
};
template< >
struct foo<int>
{
  static int doSomething() {return 5;}
};
模板
结构foo
{
静态int doSomething(){return 0;}
};
模板<>
结构foo
{
静态int doSomething(){return 5;}
};

这将编译链接并使用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; }
这样做的原因是,尽管只声明了模板函数
Foo
,但链接器确实有两个必需的定义。
在编译时,当编译器看到
main
的定义时,它可以创建
Bar
的专门化,但不能创建
Foo
的专门化。在这种情况下,它只创建对
Foo()
Foo()
的函数调用
稍后,编译器会找到它编译的
Foo
的专门化,将其保留在目标文件中,但当时不做任何其他操作。当链接器运行时,它会找到所需的一切。
更新:
所以我不知道为什么这是非法的,但出于某种原因,它似乎是编译和运行的

有没有办法使这项工作也合法

是,在使用专门化之前声明它。在您提供的示例中,简单地交换文件中的专门化和main的顺序就可以做到这一点。然而,在本例中,您仍然必须确保没有其他TU使用了专门化而没有声明它

通常,这些专门化应该在头中声明


在你的例子的范围内(即没有根本性的改变),没有其他方法可以做到这一点。

Foo的最后一个定义应该是什么意思?绝对不清楚你想做什么。提供更多详细信息。为什么不提供
int(*)(void)
函数指针作为
Bar
的模板参数,而不是C类<代码>模板int Bar(){返回某物(FOO());}。然后,用户可以直接指示调用什么函数,而不是通过为
MyClass
专门化
Foo
来间接指示调用什么函数。然后,如果愿意的话,可以用functor类替换函数指针。我认为自由函数模板通常应该声明为
inline
,以规避ODR。不确定ODR,但代码似乎违反了14.7.3/6:“如果模板。。。是显式专门化的,则应在第一次使用该专门化之前声明该专门化,该专门化将导致隐式实例化发生。。。一个想法是:在定义Bar之前,您没有要包含的专门化,在第一次使用Bar之前就应该足够了,因为实例化点就在那里。也就是说,我认为在
main()
之前声明(甚至没有定义)专门化是合法的。也没有选项?当然,函数模板可以专门化,但不能部分专门化。我喜欢
do
的蓝色。:-)有时候我希望人们不要在不理解的情况下投票-1@quamrana说了什么。你的描述正是我想要的行为。OTOH,虽然它可以编译和运行,但它是非法代码:我认为GCC和clang都会拒绝它。@BCS:我认为这段代码是合法的,因为编译main时没有定义
Foo
。如果有,gcc 4.5.2会返回一个简单的多定义错误。如果Bar未模板化,并且发出Foo调用以直接指定类型,则会生成错误消息(即,它是非法的)。除非我遗漏了什么,否则就合法性而言,这不会有什么区别(即两者都是非法的),因为无论哪种方式,Foo调用都应该在Foo定义之前进行处理。在我遇到这个问题的情况下,这都是可行的,但不能很好地概括。(请参阅我在第二个代码块中添加的注释)@BCS:您的注释中的“理想”情况是完全不可能的:必须先声明内容,然后才能使用它们,并且在使用该函数的TU中不能缺少该函数的声明。@BCS:与尝试void f(){this_function_not_declared();}不在该TU中声明被调用的函数。是的,在使用它们之前必须声明它们,但我想要的理想解决方案是使用一个只声明(并且在该TU中只声明)但未定义的模板函数。@BCS:这很好。使用前声明,定义一次。
5
5
6