locked
nested lambda function -- why does this not compile? RRS feed

  • Question

  • #include <cmath>
    
    
    namespace std
    {
    template<typename TEST, typename TRUE, typename FALSE>
    auto if_(const TEST &_rTest, const TRUE &_rTrue, const FALSE &_rFalse) -> decltype(_rTrue() + _rFalse())
    {	if (_rTest())
    		return _rTrue();
    	else
    		return _rFalse();
    }
    template<typename TEST, typename TRUE, typename FALSE, typename ARG0, typename ARG1>
    auto if_(const TEST &_rTest, const TRUE &_rTrue, const FALSE &_rFalse, const ARG0 &_rArg0, const ARG1 &_rArg1) -> decltype(_rTrue(_rArg0, _rArg1) + _rFalse(_rArg0, _rArg1))
    {	if (_rTest(_rArg0, _rArg1))
    		return _rTrue(_rArg0, _rArg1);
    	else
    		return _rFalse(_rArg0, _rArg1);
    }
    
    }
    
    
    int main(int argc, char **argv)
    {	const double lt1 = 1;
    	static const double MIN_EXP = 2;
    	static const double EXP_THRESHOLD = 3;
    	const double pParam__BSIM3dvt1 = 4;
    	const double pParam__BSIM3leff = 5;
    	const auto f1 = [](const decltype(std::exp(1.0/lt1)) &T1)
    	{	return T1 * (1.0 + 2.0 * T1);
    	};
    	const auto Theta0 = std::if_(
    		[](const decltype(1.0/lt1) &T0, const decltype(f1) &F1)
    		{	return T0 > -EXP_THRESHOLD;
    		},
     		([](const decltype(1.0/lt1) &T0, const decltype(f1) &F1)
    		{	
    #if 1
    			return [](const decltype(std::exp(T0)) &T1)
    			{	return T1 * (1.0 + 2.0 * T1);
    			}(std::exp(T0));
    #else			//auto T1 = std::exp(T0);
    			return F1(std::exp(T0));
    #endif
    		}),
    		[](const decltype(1.0/lt1) &, const decltype(f1) &)
    		{	return MIN_EXP*(1+2*MIN_EXP);
    		},
    		-0.5 * pParam__BSIM3dvt1 * pParam__BSIM3leff / lt1, f1);
    
    }
    

    Tuesday, November 1, 2011 4:44 AM

Answers

  • ok -- if a lambda function contains a nested lambda function, one needs to enlighten the compiler about the return type. Basically this means copying code and expanding this by hand. What do I have a compiler for? Code below compiles now.

    #include <cmath>
    
    
    //#define decltype(a) double
    namespace std
    {
    template<typename TEST, typename TRUE, typename FALSE>
    auto if_(const TEST &_rTest, const TRUE &_rTrue, const FALSE &_rFalse) -> decltype(_rTrue() + _rFalse())
    {	if (_rTest())
    		return _rTrue();
    	else
    		return _rFalse();
    }
    template<typename TEST, typename TRUE, typename FALSE, typename ARG>
    auto if_(const TEST &_rTest, const TRUE &_rTrue, const FALSE &_rFalse, const ARG &_rArg) -> decltype(_rTrue(_rArg) + _rFalse(_rArg))
    {	if (_rTest(_rArg))
    		return _rTrue(_rArg);
    	else
    		return _rFalse(_rArg);
    }
    
    template<typename TEST, typename TRUE, typename FALSE, typename ARG0, typename ARG1>
    auto if_(const TEST &_rTest, const TRUE &_rTrue, const FALSE &_rFalse, const ARG0 &_rArg0, const ARG1 &_rArg1) -> decltype(_rTrue(_rArg0, _rArg1) + _rFalse(_rArg0, _rArg1))
    {	if (_rTest(_rArg0, _rArg1))
    		return _rTrue(_rArg0, _rArg1);
    	else
    		return _rFalse(_rArg0, _rArg1);
    }
    
    }
    
    
    int main(int argc, char **argv)
    {	const double lt1 = 1;
    	static const double MIN_EXP = 2;
    	static const double EXP_THRESHOLD = 3;
    	const double pParam__BSIM3dvt1 = 4;
    	const double pParam__BSIM3leff = 5;
    	const auto f1 = [](const decltype(std::exp(1.0/lt1)) &T1)
    	{	return T1 * (1.0 + 2.0 * T1);
    	};
    	const auto Theta0 = std::if_(
    		[](const decltype(1.0/lt1) &T0)
    		{	return T0 > -EXP_THRESHOLD;
    		},
     		([](const decltype(1.0/lt1) &T0) -> decltype(std::exp(T0) * (1.0 + 2.0 * std::exp(T0)))
    		{	
    #if 1
    			return (([](const decltype(std::exp(T0)) & T1) -> decltype(T1 * (1.0 + 2.0 * T1))
    			{	return T1 * (1.0 + 2.0 * T1);
    			})(std::exp(T0)));
    #else			//auto T1 = std::exp(T0);
    			return F1(std::exp(T0));
    #endif
    		}),
    		[](const decltype(1.0/lt1) &)
    		{	return MIN_EXP*(1+2*MIN_EXP);
    		},
    		-0.5 * pParam__BSIM3dvt1 * pParam__BSIM3leff / lt1);
    
    }

    • Marked as answer by ExcessPhase Thursday, November 3, 2011 1:26 AM
    Wednesday, November 2, 2011 3:10 AM

All replies

  • all the decltype() stuff is done, since usually variable lt1 is not of type double.

    Applying an operation like 1.0/lt1 creates a new type.

    Passing the lambda function is a workaround.

    But I'm wondering, why I cannot use nested lambda functions.

    Or even only a temporary variable -- the following code also does not compile

    (to replace the internal lamba function):

     

    auto T1 = std::exp(T0);

    return T1 * (1.0 + 2.0 * T1);

    Tuesday, November 1, 2011 4:48 AM
  • g++ (GCC) 4.5.3 compiles this fine!

    Using the option -std=c++0x of couse.

    In visual C++ 2010 I'm getting:

     

    ------ Build started: Project: bug_lambda, Configuration: Debug Win32 ------

     

    Build started 11/1/2011 7:23:04 PM.

     

    InitializeBuildStatus:

     

    Touching "Debug\bug_lambda.unsuccessfulbuild".

     

    ClCompile:

     

    Source1.cpp

     

    c:\users\peter\bug_lambda\source1.cpp(50): error C2893: Failed to specialize function template ''unknown-type' std::if_(const TEST &,const TRUE &,const FALSE &,const ARG0 &,const ARG1 &)'

     

    With the following template arguments:

     

    '`anonymous-namespace'::<lambda1>'

     

    '`anonymous-namespace'::<lambda2>'

     

    '`anonymous-namespace'::<lambda3>'

     

    'double'

     

    '`anonymous-namespace'::<lambda0>'

     

    c:\users\peter\bug_lambda\source1.cpp(50): error C2780: ''unknown-type' std::if_(const TEST &,const TRUE &,const FALSE &)' : expects 3 arguments - 5 provided

     

    c:\users\peter\bug_lambda\source1.cpp(7) : see declaration of 'std::if_'

     

    c:\users\peter\bug_lambda\source1.cpp(50): fatal error C1903: unable to recover from previous error(s); stopping compilation

     

    Build FAILED.

     

    Time Elapsed 00:00:02.23

     

    ========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========

     

     

    Wednesday, November 2, 2011 2:23 AM
  • ok -- if a lambda function contains a nested lambda function, one needs to enlighten the compiler about the return type. Basically this means copying code and expanding this by hand. What do I have a compiler for? Code below compiles now.

    #include <cmath>
    
    
    //#define decltype(a) double
    namespace std
    {
    template<typename TEST, typename TRUE, typename FALSE>
    auto if_(const TEST &_rTest, const TRUE &_rTrue, const FALSE &_rFalse) -> decltype(_rTrue() + _rFalse())
    {	if (_rTest())
    		return _rTrue();
    	else
    		return _rFalse();
    }
    template<typename TEST, typename TRUE, typename FALSE, typename ARG>
    auto if_(const TEST &_rTest, const TRUE &_rTrue, const FALSE &_rFalse, const ARG &_rArg) -> decltype(_rTrue(_rArg) + _rFalse(_rArg))
    {	if (_rTest(_rArg))
    		return _rTrue(_rArg);
    	else
    		return _rFalse(_rArg);
    }
    
    template<typename TEST, typename TRUE, typename FALSE, typename ARG0, typename ARG1>
    auto if_(const TEST &_rTest, const TRUE &_rTrue, const FALSE &_rFalse, const ARG0 &_rArg0, const ARG1 &_rArg1) -> decltype(_rTrue(_rArg0, _rArg1) + _rFalse(_rArg0, _rArg1))
    {	if (_rTest(_rArg0, _rArg1))
    		return _rTrue(_rArg0, _rArg1);
    	else
    		return _rFalse(_rArg0, _rArg1);
    }
    
    }
    
    
    int main(int argc, char **argv)
    {	const double lt1 = 1;
    	static const double MIN_EXP = 2;
    	static const double EXP_THRESHOLD = 3;
    	const double pParam__BSIM3dvt1 = 4;
    	const double pParam__BSIM3leff = 5;
    	const auto f1 = [](const decltype(std::exp(1.0/lt1)) &T1)
    	{	return T1 * (1.0 + 2.0 * T1);
    	};
    	const auto Theta0 = std::if_(
    		[](const decltype(1.0/lt1) &T0)
    		{	return T0 > -EXP_THRESHOLD;
    		},
     		([](const decltype(1.0/lt1) &T0) -> decltype(std::exp(T0) * (1.0 + 2.0 * std::exp(T0)))
    		{	
    #if 1
    			return (([](const decltype(std::exp(T0)) & T1) -> decltype(T1 * (1.0 + 2.0 * T1))
    			{	return T1 * (1.0 + 2.0 * T1);
    			})(std::exp(T0)));
    #else			//auto T1 = std::exp(T0);
    			return F1(std::exp(T0));
    #endif
    		}),
    		[](const decltype(1.0/lt1) &)
    		{	return MIN_EXP*(1+2*MIN_EXP);
    		},
    		-0.5 * pParam__BSIM3dvt1 * pParam__BSIM3leff / lt1);
    
    }

    • Marked as answer by ExcessPhase Thursday, November 3, 2011 1:26 AM
    Wednesday, November 2, 2011 3:10 AM