在compiletime依赖于编译器和优化标志的模板和constexpr扣除 [英] Template and constexpr deduction at compiletime dependent on compiler and optimization flags

查看:88
本文介绍了在compiletime依赖于编译器和优化标志的模板和constexpr扣除的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

以下问题来自一个更大的代码。因此,一些表达式似乎是一个过度的或不必要的,但是对原始代码至关重要。

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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆