在compiletime依赖于编译器和优化标志的模板和constexpr扣除 [英] Template and constexpr deduction at compiletime dependent on compiler and optimization flags
问题描述
以下问题来自一个更大的代码。因此,一些表达式似乎是一个过度的或不必要的,但是对原始代码至关重要。
The following question is condensed from a much larger code. Therefore some expressions seem to be an overkill or unnecessary, but are crucial to the original code.
考虑一个结构体,它包含编译时常数和一个简单的容器类:
Consider having a struct, which contains compile time constants and a simple container class:
template<typename T> struct CONST
{
static constexpr T ONE()
{
return static_cast<T>( 1 );
}
};
template<typename T> class Container
{
public:
using value_type = T;
T value;
};
现在有一个模板函数,对于提供 value_type
:
Now having a template function, that has a "specialization" for types offering a value_type
:
template<typename T> void doSomething( const typename T::value_type& rhs )
{}
预期,这应该工作:
template<typename T> class Tester
{
public:
static constexpr T ONE = CONST<T>::ONE();
void test()
{
doSomething<Container<T>>( ONE );
}
};
有趣的是,编译器不会抱怨 Tester< T> :: ONE
,但其用法。此外,如果我使用 CONST< T> :: ONE()
或甚至 static_cast< T>(ONE)
而不是在函数调用中的 ONE
。但是,在编译时都应该知道它们,因此可以使用。
所以我的第一个问题是:编译器在情况下,它的工作原理,甚至在编译时进行计算。
The interesting point is, that the compiler does not complain about the definition of Tester<T>::ONE
, but its usage. Further it does not complain, if I use CONST<T>::ONE()
or even static_cast<T>( ONE )
instead of ONE
in the function call. However, both should be known at compile time and therefore usable.
So my first question is: Does the compiler in the cases, where it works, even do the calculations at compile time?
code> g ++ - 5 , g ++ - 6
和 clang-3.8
编译器使用 -std = c ++ 14
标志。他们都抱怨
I checked it with the g++-5
, g++-6
and the clang-3.8
compiler using the -std=c++14
flag. They all complain
undefined reference to `Tester<int>::ONE'
虽然所有使用的功能,据我所知,在标准,因此应该支持。有趣的是,只要我添加一个优化标志 O1
, O2
或 O3
。所以我的第二个问题是:有编译器的策略只做编译时计算,如果优化标志是活动的?我会期望,至少被声明为编译时常数的东西总是被推导出来的。
although all used features are, as far as I know, in the standard and should therefore be supported. Interestingly the compilation is successful as soon as I add an optimization flag O1
, O2
or O3
. So my second question is: Is there an strategy of the compiler doing compile time calculations only, if optimization flags are active? I would have expected that at least things, that are declared as compile time constant are always deduced!
我的问题的最后一部分涵盖了NVIDIA nvcc
编译器(8.0版)。因为我只能通过 -std = c ++ 11
,它可能是一些功能一般不包括。但是,使用上述主机编译器之一,它会引发
The last part of my question covers the NVIDIA nvcc
compiler (version 8.0). As I can only pass -std=c++11
to it, it may be that some features are generally not covered. However, using one of the host compiler above, it complains
error: identifier "Tester<int> ::ONE" is undefined in device code
这显然是与上述相同的问题,但虽然上面的问题是更学术的(因为我可以简单地使用优化标志来摆脱问题),这里它是一个真正的问题(关于这个事实,我不知道,当我使用上面提到的解决方法时,在编译时所做的 - 这也是丑陋的)。所以我的第三个问题是:在设备代码中是否还有使用优化的方法?
even if an optimization flag is passed! This is obviously the very same problem as above, but while the questions above are more academical (because I can simply use an optimization flag to get rid of the problem), here it is really a problem (concerning the fact that I do not know, what is done at compile time when I use the workarounds mentioned above - and this is also uglier). So my third question is: Is there a way of using the optimizations also in device code?
以下代码是纯主机和nvcc编译器的MWE:
The following code is an MWE for pure host and also for the nvcc compiler:
#include <iostream>
#include <cstdlib>
#ifdef __CUDACC__
#define HD __host__ __device__
#else
#define HD
#endif
template<typename T> struct CONST
{
HD static constexpr T ONE()
{
return static_cast<T>( 1 );
}
};
template<typename T> class Container
{
public:
using value_type = T;
T value;
};
template<typename T> HD void doSomething( const typename T::value_type& rhs ) {}
template<typename T> class Tester
{
public:
static constexpr T ONE = CONST<T>::ONE();
HD void test()
{
doSomething<Container<T>>( ONE );
// doSomething<Container<T>>( static_cast<T>( ONE ) );
// doSomething<Container<T>>( CONST<T>::ONE() );
}
};
int main()
{
using t = int;
Tester<t> tester;
tester.test();
return EXIT_SUCCESS;
}
提前感谢!
推荐答案
这两者之间的区别:
doSomething<Container<T>>( ONE );
,而不是这两个:
doSomething<Container<T>>( static_cast<T>( ONE ) );
doSomething<Container<T>>( CONST<T>::ONE() );
是在第一种情况下,你直接绑定一个引用 ONE
和其他你不是。更具体地说,你在第一种情况下是 odr-using ONE
,而不是其他两个。当您 odr使用实体时,需要一个定义, ONE
目前已声明但未定义。
is that in the first case you're binding a reference directly to ONE
and the others you are not. More specifically, you are odr-using ONE
in the first case but not the other two. When you odr-use an entity, it needs a definition, and ONE
is currently declared but not defined.
您需要定义它:
template<typename T>
class Tester
{
public:
// declaration
static constexpr T ONE = CONST<T>::ONE();
// ..
};
// definition
template <typename T>
constexpr T Tester<T>::ONE;
这篇关于在compiletime依赖于编译器和优化标志的模板和constexpr扣除的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!